How to save Array of custom objects to NSUserDefaults

Using NSCoding, NSKeyedArchiver and NSKeyedUnarchiver to save array of custom objects to NSUserDefaults

NSCoding protocol



NSCoding protocol enables an object to be encoded or decoded for archiving and saving to disk.

It declares two methods that your object must implement in order to be encoded and decoded.

So our first step is to adopt the NSCoding protocol and implements its methods.

import UIKit

class Item: NSObject, NSCoding {
    
    var itemID: Int?
    var itemName: String?
    
    init(json: [String: Any])
    {
        self.itemID = json["itemID"] as? Int
        self.itemName = json["itemName"] as? String
    }
    
    func encode(with aCoder: NSCoder)
    {
        aCoder.encode(self.itemID, forKey: "itemID")
        aCoder.encode(self.itemName, forKey: "itemName")
    }
    
    required init?(coder aDecoder: NSCoder)
    {
        self.itemID = aDecoder.decodeObject(forKey: "itemID") as? Int
        self.itemName = aDecoder.decodeObject(forKey: "itemName") as? String
    }
    
}

Here we created our Item class and adopted the NSCoding protocol and implemented its two methods: init(coder) and encode(with)

Now lets create two instances of this class and add them to an array

        let itemA = Item(json:["itemID": 1, "itemName": "item number a"])
        let itemB = Item(json:["itemID": 2, "itemName": "item number b"])
        
        let itemsArray = [itemA, itemB]

Before saving the array let me introduce to you the NSKeyedArchiver and his brother NSKeyedUnarchiver

NSKeyedArchiver and NSKeyedUnarchiver classes

They are subclasses of the NSCoder class.

The NSKeyedArchiver class encodes the object into architecture-independent format that can be stored in a file.

The NSKeyedUnarchiver decodes the data in an archive and creates a sets of objects equivalent to the original set.

Keyed archive means that all objects and values are given names or keys so values can be requested by their name when decoded.

On the other hand non-keyed archive depends on the order so all objects must decoded in the same order in which they were encoded.

Back to our example lets save the array to NSUserDefaults using NSKeyedArchiver

let encodedData = NSKeyedArchiver.archivedData(withRootObject: itemsArray)
UserDefaults.standard.set(encodedData, forKey: "items")

Finally lets read it back from NSUserDefaults using NSKeyedUnarchiver

let decodedArray = NSKeyedUnarchiver.unarchiveObject(with: UserDefaults.standard.object(forKey: "items") as! Data) as! [Item]

print("\(decodedArray[0].itemName)\(decodedArray[1].itemName)")

You should see the item a and b names printed in the console.

Leave a Reply

Your email address will not be published. Required fields are marked *