Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to archive and unarchive custom objects in Swift? Or how to save custom object to NSUserDefaults in Swift?

I have a class

class Player {

    var name = ""

    func encodeWithCoder(encoder: NSCoder) {
        encoder.encodeObject(name)
    }

    func initWithCoder(decoder: NSCoder) -> Player {
        self.name = decoder.decodeObjectForKey("name") as String
        return self
    }

    init(coder aDecoder: NSCoder!) {
        self.name = aDecoder.decodeObjectForKey("name") as String
    }

    init(name: String) {
        self.name = name
    }
}

and i want to serialise it and save to user defaults.

First of all I'm not sure how to correctly write encoder and decoder. So for init i wrote two methods.

When i try to execute this code:

func saveUserData() {
    let player1 = Player(name: "player1")
    let myEncodedObject = NSKeyedArchiver.archivedDataWithRootObject(player1)
    NSUserDefaults.standardUserDefaults().setObject(myEncodedObject, forKey: "player")
}

app crashes and i get this message:

*** NSForwarding: warning: object 0xebf0000 of class '_TtC6GameOn6Player' does not implement methodSignatureForSelector: -- trouble ahead

What do i do wrong?

like image 572
tadasz Avatar asked Jul 09 '14 16:07

tadasz


People also ask

How can you store object to UserDefaults?

To store them in UserDefaults, we need to implement or confirm Codable to the user-defined class or struct. Codable is a typealias of Decodable & Encodable protocols. It adds the functionality of Encoding and Decoding to the class or struct.


2 Answers

In Swift 4 you don't need NSCoding anymore! There is a new protocol called Codable!

class Player: Codable {

    var name = ""

    init(name: String) {
        self.name = name
    }
}

And Codable also supports Enums and Structs so you can rewrite your player class to a struct if you want!

struct Player: Codable {
    let name: String
}

To save your player in Userdefaults:

let player = Player(name: "PlayerOne")
try? UserDefaults.standard.set(PropertyListEncoder().encode(player), forKey: "player")

Note: PropertyListEncoder() is a class from the framework Foundation

To Retrieve:

let encoded = UserDefault.standard.object(forKey: "player") as! Data
let storedPlayer = try! PropertyListDecoder().decode(Player.self, from: encoded)

For more information, read https://developer.apple.com/documentation/swift/codable

like image 57
Jeroen Bakker Avatar answered Oct 17 '22 09:10

Jeroen Bakker


NSKeyedArchiver will only work with Objective-C classes, not pure Swift classes. You can bridge your class to Objective-C by marking it with the @objc attribute or by inheriting from an Objective-C class such as NSObject.

See Using Swift with Cocoa and Objective-C for more information.

like image 37
jatoben Avatar answered Oct 17 '22 10:10

jatoben