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
The NSCoding protocol declares the two methods that a class must implement so that instances of that class can be encoded and decoded. This capability provides the basis for archiving (where objects and other structures are stored on disk) and distribution (where objects are copied to different address spaces).
NSCoder declares the interface used by concrete subclasses to transfer objects and other values between memory and some other format. This capability provides the basis for archiving (storing objects and data on disk) and distribution (copying objects and data items between different processes or threads).
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With