简体   繁体   中英

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:

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. 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):

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:

[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?

CGPoint (and its Cocoa's twin NSPoint ) are structs, ie value type, so you can't encode them directly. Wrap them in 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.

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)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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