简体   繁体   English

如何在Swift中使用NSCoder对CGPoints数组进行编码?

[英]How to encode an array of CGPoints with NSCoder in Swift?

I am trying to save a copy of my custom class to a file, my class has 2 arrays of CGPoints which I append to every so often, they look like this: 我正在尝试将自定义类的副本保存到文件中,我的类具有2个CGPoints数组,我经常将它们附加到它们,它们看起来像这样:

class BlockAttributes: NSObject {
    var positions:[CGPoint] = []
    var spawns:[CGPoint] = []
}

Everything is working great as far as just as using and accessing the class goes, but archiving it does not work. 就像使用和访问该类一样,一切工作都很好,但是将其归档是无效的。 I can archive arrays of Strings, Bools, and Ints just fine in my other classes but my game fails every time I try to use NSCoder to encode my arrays of CGPoints. 我可以在其他类中很好地归档Strings,Bools和Ints数组,但是每次尝试使用NSCoder编码CGPoints数组时,我的游戏都会失败。 Here is my code for archiving: 这是我的存档代码:

func encodeWithCoder(coder: NSCoder!) {
    coder.encodeObject(positions, forKey: "positions")
    coder.encodeObject(spawns, forKey: "spawns")
}

.... ....

class ArchiveData: NSObject {

    var documentDirectories:NSArray = []
    var documentDirectory:String = ""
    var path:String = ""

    func saveData(data: BlockAttributes) {
        documentDirectories = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)
        documentDirectory = documentDirectories.objectAtIndex(0) as! String
        path = documentDirectory.stringByAppendingPathComponent("data.archive")

        if NSKeyedArchiver.archiveRootObject(data, toFile: path) {
            print("Success writing to file!")
        } else {
            print("Unable to write to file!")
        }
    }

    func retrieveData() -> NSObject {
        var dataToRetrieve = BlockAttributes()
        documentDirectories = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)
        documentDirectory = documentDirectories.objectAtIndex(0) as! String
        path = documentDirectory.stringByAppendingPathComponent("data.archive")
        if let dataToRetrieve2 = NSKeyedUnarchiver.unarchiveObjectWithFile(path) as? BlockAttributes {
            dataToRetrieve = dataToRetrieve2 as BlockAttributes
        }
        return(dataToRetrieve)
    }
}

.... And to save: ....并保存:

let archiveData = ArchiveData()
archiveData.saveData(myBlockActionsObject)

I even tried creating my own custom class to save the CGPoints to, which I call MyCGPoint (I read somewhere on SO that creating custom classes for some data types resolves some NSCoder issues): 我什至尝试创建自己的自定义类来将CGPoint保存到我称之为MyCGPoint的位置(我在SO上的某个地方读到,为某些数据类型创建自定义类可以解决一些NSCoder问题):

class MyCGPoint: NSObject {
    var x: CGFloat = 0.0
    var y: CGFloat = 0.0

    init(X: CGFloat, Y: CGFloat) {
        x = X
        y = Y
    }

    override init() {

    }
}

.... ....

class BlockAttributes: NSObject {
    var positions:[MyCGPoint] = []
    var spawns:[MyCGPoint] = []
}

But alas, I am still getting this error: 但是a,我仍然收到此错误:

[Game.MyCGPoint encodeWithCoder:]:
unrecognized selector sent to instance 0x137f1d1a0 Game[20953:5814436]
*** Terminating app due to uncaught exception 'NSInvalidArgumentException',
reason: '-[Game.MyCGPoint encodeWithCoder:]:
unrecognized selector sent to instance 0x137f1d1a0'

Any idea how I can use encodeObject to encode my array of CGPoints/MyCGPoints? 知道如何使用encodeObject编码CGPoints / MyCGPoints数组吗?

CGPoint (and its Cocoa's twin NSPoint ) are structs, ie value type, so you can't encode them directly. CGPoint (及其可可的孪生NSPoint )是结构,即值类型,因此您不能直接对其进行编码。 Wrap them in NSValue : 将它们包装在NSValue

let positionValues = positions.map { NSValue(point:$0) }
let spawnValues    = spawns.map    { NSValue(point:$0) }

coder.encodeObject(positionValues, forKey: "positions")
coder.encodeObject(spawnValues, forKey: "spawns")

// Decode:
positons = (coder.decodeObjectForKey("positions") as! [NSValue]).map { $0.pointValue }
spawns   = (coder.decodeObjectForKey("spawns")    as! [NSValue]).map { $0.pointValue }

When you write your custom wrapper class, you have to make it compliant with NSCoding too, which NSValeu had already done for you, for free. 编写自定义包装器类时,还必须使其与NSCoding兼容,而NSValeu已经为您免费完成。

You can convert them to and from strings: 您可以将它们转换为字符串:

//To string
let point = CGPointMake(0, 0)
let string = NSStringFromCGPoint(point)
//Or if you want String instead of NSString
let string = String(point)

//From string
let point2 = CGPointFromString(string)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM