NSCoding with Nested Custom Objects?
Asked Answered
C

2

11

I have a series of nested objects that I am needing to put through the NSCoding protocol so that I can save the top level object into NSUserDefaults.

Here is the structure of objects:

'Instructor' class

  • NSMutableArray that holds instances of...

'Class' class

  • NSMutableArray that holds instances of...

'Student' class

  • Name Property
  • Number Property
  • Money Property

I am needing to save an instance of Instructor to NSUserDefaults or to documents for the app. As you can see the Instructor object is holding an array that is then holding instances of a class. That class object is holding instances of students.

Is the NSCoding protocol recursive? What I mean by that is if I add the NSCoding protocol to each class, I could then save an Instructor object and it would recursively encode the contained objects?

Would it then work the same way while decoding? I could just decode the one instructor class and it would recursively decode the objects contained because they also conform to the NSCoding protocol?

How could I go about setting this up?

Cardinal answered 25/9, 2013 at 19:7 Comment(2)
NSUserDefaults isn't an appropriate place to store that kind of user data. Why not just store it as a custom document in the Documents directory?Griswold
That's why I said I will save it to either NSUserDefaults or to documents. The reason I would consider NSUserDefaults is because the size of the instructor object would be very small.Cardinal
I
18

Yes, you can (and probably should) write your support for NSCoding to be recursive. That's how NSCoding is supposed to work.

When your implement encodeWithCoder, simply call

[coder encodeObject: aProperty forKey: @"propertyName"];

on all your object's properties, including it's container properties.

Then make sure every object in your object's object graph also conforms to NSCoding.

For scalar properties, you can save the scalar value using NSCoder methods like encodeInt:forKey:

To save an object that conforms to NSCoding to user defaults, first convert it to NSData using the NSKeyedArchiver class method archivedDataWithRootObject, then save the resulting data into defaults. Quite simple, really.

Impersonalize answered 25/9, 2013 at 19:42 Comment(4)
When I convert to NSData using NSKeyedArchiver, does that automatically run the NSCoding protocol? That way I execute that one statement and it will encode everything.Cardinal
Jonathan, yes, that's how it works. You can call a method like archivedDataWithRootObject to archive an object. That will archive the object and any of it's child objects by calling their NSCoding methods, and return the results as NSData.Impersonalize
And how do you go the other direction?Fallen
You use the NSKeyedUnarchiver methods like unarchiveObjectWithData or unarchiveObjectWithFile.Impersonalize
S
4

NSCoding isn't magic so it will work 'recursively' if your implementation of the encoding and decoding methods tells it to be.

Implement the NSCoding methods and pass the data to be encoded to the encoder. Implement the NSCoding methods in all of your custom classes so that when you encode the array all of the contents can be processed appropriately.

Be sure to call super if the classes superclass also implements NSCoding.

e.g.

- (void)encodeWithCoder:(NSCoder *)encoder {
    [encoder encodeObject:self.arrayOfClasses forKey:@"arrayOfClasses"];
}

- (id)initWithCoder:(NSCoder *)decoder {
    self.arrayOfClasses = [decoder decodeObjectForKey:@"arrayOfClasses"];
}
Scintillant answered 25/9, 2013 at 19:10 Comment(5)
So you're saying that if I do implement the NSCoding methods on each custom class it will encode them when I encode that top level array? None of these classes have super classes.Cardinal
If you implement it to do so. You are passed an NSCoder, you need to tell it what to do. Your classes should at least inherit from NSObject.Scintillant
Could you show me an example of how to do it? I have never worked with the NSCoding protocol so I'm not exactly sure how to pass an NSCoder to these classes. My classes do inherit from NSObject, I was referring to them not inheriting from another custom super class.Cardinal
Thank you for adding that code. I do have that implementation in all of my classes, but when I encode the arrayOfClasses, will it automatically encode the objects contained within that array?Cardinal
It should, have you tested it?Scintillant

© 2022 - 2024 — McMap. All rights reserved.