Objects saved with NSKeyedArchiver and loaded back are nil

3.6k views Asked by At

I save a custom object Bottle with the following code

class Bottle: NSObject, NSCoding {

    let id: String!
    let title: String!
    let year: Int!
    let icon: UIImage!


    init(id: String, title: String, year: Int, icon: UIImage) {
        self.id = id
        self.title = title
        self.year = year
        self.icon = icon
    }

    override init(){}

    var bottlesArray = NSMutableArray()

    // code inspired from http://stackoverflow.com/questions/24238868/swift-nscoding-not-working

    required init(coder aDecoder: NSCoder) {
        self.bottlesArray = aDecoder.decodeObjectForKey("bottleArray") as NSMutableArray
    }

    func encodeWithCoder(aCoder: NSCoder) {
        aCoder.encodeObject(bottlesArray, forKey: "bottleArray")
    }

    func add(bottle: Bottle) {
        self.bottlesArray.addObject(bottle)
    }

    func save() {
        let data = NSKeyedArchiver.archivedDataWithRootObject(self)
        NSUserDefaults.standardUserDefaults().setObject(data, forKey: "bottleList")
    }

    class func loadSaved() -> Bottle? {
        if let data = NSUserDefaults.standardUserDefaults().objectForKey("bottleList") as? NSData {
            return NSKeyedUnarchiver.unarchiveObjectWithData(data) as? Bottle
        }
        return nil
    }

    func saveBottle(bottle: Bottle) {
        let bottleList = Bottle.loadSaved()
        bottleList?.add(bottle)
        bottleList?.save()
        let bottleList2 = Bottle.loadSaved()
        println(bottleList2?.bottlesArray.count)
        println(bottleList2?.bottlesArray[0].title)
    }
}

I save 3 bottles. The two last println print me 3 and nil so there is indeed 3 elements in my array but they are nil and I do not understand why. I have another class that saves String instead of Bottle and that doesn't have an init function like the init(id: String, title: String, year: Int, icon: UIImage) one and it works fine.

Here is how I save my bottles:

var bottleLoaded = Bottle.loadSaved()!
var bottleToSave = Bottle(id: bottleID, title: bottleName, year: bottleYear, icon: UIImage(data:bottleIconData)!)
bottleLoaded.saveBottle(bottleToSave)    

and that's it.

I also have in a previous ViewController the following code in order to "initialize" the memory

let bottleList = Bottle()
bottleList.save()    

I also already tried to add NSUserDefaults.standardUserDefaults().synchronize() but it doesn't change anything, my loaded objects are still nil.

1

There are 1 answers

0
Loïc Gardiol On BEST ANSWER

You need to save and retrieve all the attributes of Bottle in the NSCoding methods:

required init(coder aDecoder: NSCoder) {
    self.bottlesArray = aDecoder.decodeObjectForKey("bottleArray") as NSMutableArray
    self.id = aDecoder.decodeObjectForKey("id") as String
    //etc. same for title, year, and icon (use decodeIntegerForKey: for year)
}

func encodeWithCoder(aCoder: NSCoder) {
    aCoder.encodeObject(bottlesArray, forKey: "bottleArray")
    aCoder.encodeObject(self.id, forKey: "id")
    //etc. same for title, year, and icon (use encodeInteger:forKey: for year)
}