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?

BlueBear
  • 7,469
  • 6
  • 32
  • 47
  • `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? – jlehr Sep 25 '13 at 20:39
  • 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. – BlueBear Sep 25 '13 at 22:08

2 Answers2

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.

Duncan C
  • 128,072
  • 22
  • 173
  • 272
  • 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. – BlueBear Sep 25 '13 at 20:02
  • 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. – Duncan C Jan 08 '14 at 19:39
  • And how do you go the other direction? – William Entriken Dec 20 '15 at 07:19
  • You use the NSKeyedUnarchiver methods like `unarchiveObjectWithData` or `unarchiveObjectWithFile`. – Duncan C Dec 20 '15 at 12:08
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"];
}
Wain
  • 118,658
  • 15
  • 128
  • 151
  • 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. – BlueBear Sep 25 '13 at 19:13
  • 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`. – Wain Sep 25 '13 at 19:15
  • 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. – BlueBear Sep 25 '13 at 19:17
  • 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? – BlueBear Sep 25 '13 at 19:24
  • It should, have you tested it? – Wain Sep 25 '13 at 19:28