What does it mean to be NSCoding-Compliant?
Asked Answered
P

2

8

So I'm going through this tutorial, and I've finally figured out how to archive an object using NSCoding, and also to initialize it from the filesystem again with the failable initializer.

// To encode the object in the first place

func encode(with aCoder: NSCoder) {
        aCoder.encode(name, forKey: "name")
}

// To 're-initialize' the object

required init?(coder aDecoder: NSCoder) {
    self.name = aDecoder.decodeObject(forKey: "name") as! String
    super.init()
}

However, I'm still a little uncertain about how this whole process works at a high level. Please tell me where my thinking is incorrect.

1) If your object adopts the NSCoding protocol, you can use the encode(with:) function in order to have an NSCoder object passed through the function and perform an 'encode' method, passing your object's instance property (which is an object itself) as the first argument, and a string representing a key as the second value.

2) This is a recursive process, so essentially, the reason you are passing your object's instance property (i.e. name) is so that THAT property (which is an object) can be sent the encode message, and so on and so forth down the line until it no longer reaches an NSCoding adopter.

3)The aDecoder object can also decode things, so upon initialization of your custom object, you'll want to use the failable initializer to decode whatever object was set for the ambiguous string key that you used.

Here's what I really don't understand...

How does the aDecoder object know which individual object to use for the set of keys? For instance, let's say I have 10 dog object instances. When the system passes aDecoder through, and I use the decodeObject method on it, and it sets self.name to the value of that decoded object by key, how does aDecoder know that this dog's name was saved as "Jack", and not to grab one of the other dog instance's names by accident, such as "Jodi"?

In other words, once you encode an object's properties, how does the file system know to keep object instance A's properties separate from object instance B's properties, thus in doing so, when the app is booted back up and object A gets initialized, it only grabs object A's properties?

Thanks

Purine answered 19/12, 2016 at 23:49 Comment(0)
F
1

I think the piece you're missing (correct me if I'm wrong) is that NSCoding is not a database. It's a protocol which defines a way to serialize an object.

The NSCoder used for decoding knows which object because that's the one which was encoded into it. For example, if you used an NSKeyedArchiver (an NSCoder subclass, and a common way to use NSCoding) to save your Dog to a file on disk called "/tmp/jack.dog", then you could later use an NSKeyedUnarchiver to load "/tmp/jack.dog", and deserialize it back into a Dog instance. It "knows which object" because that's the (only) one that was saved to that file.

It doesn't have to be a file. The data could be saved anywhere at all.

Fenestration answered 19/12, 2016 at 23:55 Comment(1)
To that, I would add that the object graph is stored hierarchically descending from a single root object. If that object graph contains loops, it only gets written once, and subsequent spots where that object is referenced instead have back-references to the first copy of the object.Violetvioleta
A
1

So, you might actually use a keyed archiver by calling class func archivedData(withRootObject rootObject: Any) -> Data', passing it some object and getting back an instance of Data that you can then persist to disk.

What is that data? It's a representation of the object passed in, the rootObject, which includes the name of the objects class and a set of keys and associated values (where those associated values are similarly encoded). So it's a hierarchical representation of an object graph, with the associated object data.

Say that object was your Dog instance, it knows that class, and all of the associated dog attributes.

Say instead that the object was an array of 10 Dog instances, now the array will store a set of encoded objects against their indexes, each encoded object knowing it's class and associated dog attributes, and the encoder stores that the root object is an array.

So, it's this extra data that is managed by the encoder (and used by the decoder) which allows it to know what to do when you pass it some data (from a file for example) and ask for it to be decoded.

Anatole answered 22/12, 2016 at 15:45 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.