Search code examples
swiftcocoaarchivenscoding

The required encoding function doesn't shown in a working code


serialization and deserialization is done by the two method defined in the NSCoding protocol as follow

encodeWithCoder(_ aCoder: NSCoder) {
    // Serialize your object here
}

init(coder aDecoder: NSCoder) {
    // Deserialize your object here
}

In my own ViewController (inherited from UITableViewController), I have a Array which contain my own object named Item and I do implemented the init(coder aDecoder: NSCoder) initial function. The Item is defined as follow

class Item: NSObject, NSCoding {
    var text = ""
    var checked = false

    func toggleChecked() {
            checked = !checked
    }

    func encode(with aCoder: NSCoder) {
        aCoder.encode(self.text, forKey: "SLAText")
        aCoder.encode(self.checked, forKey: "SLAChecked")
    }

    required init?(coder aDecoder: NSCoder) {
        self.text = aDecoder.decodeObject(forKey: "SLAText") as! String
        self.checked = aDecoder.decodeBool(forKey: "SLAChecked")
        super.init()
    }

    override init() {
        super.init()
    }
}

Instead implement the function encode(with: NSCoder) I defined my own serialization function named saveItems()

 func saveItems() {
        let data = NSMutableData()
        let archiver = NSKeyedArchiver(forWritingWith: data)

        archiver.encode(items, forKey: "ItemLists") //items is a array of type [Item]
        archiver.finishEncoding()

        data.write(to: dataFilePath(), atomically: true)      
    }

Question

Why the code is working with out implement the required NSCoding function? The code is simplified from a example of the book I'm studying, I didn't find the encodeWithCoder(_ aCoder: NSCoder) function at all. Isn't the required means you have to implemented it?

Thanks for your time and help


Solution

  • Why the code is working with out implement the required NSCoding function?

    This is not true.

    NSCoding is a protocol

    First of all NSCoding is a protocol, not a function. And in order to conform a type to NSCoding you need to implement a method and an initializer

    public func encode(with aCoder: NSCoder)
    public init?(coder aDecoder: NSCoder)
    

    Why does your code work?

    Let's look at what you are doing

    archiver.encode(items, forKey: "ItemLists")
    

    Here items is defined as [Item] which is and array of Item(s). And Array does conform to NSCoding. This can be easily tested by writing

    let nums = [1, 2, 3]
    
    if nums is NSCoding {
        print("Array does conform to NSCoding")
    } else {
        print("Array does NOT conform to NSCoding")
    }
    

    The result is

    Array does conform to NSCoding
    

    Conclusion

    Of course to work properly the element inside of the array must be conform to NSCodable too. And since the generic type of your Array is Item (which you made conform to NSCodable) the mechanism does work properly.