Popular Tags

Who's online

There are currently 0 users and 59 guests online.

User login

I've had need to save custom objects to file and then restore them the next time my app runs. Fortunately, this is a snap when you use the wonderful thing that is NSCoding, a protocol defined in the Foundation framework that specifies the following two required methods:

- (void) encodeWithCoder:(NSCoder*)encoder;
- (id) initWithCoder:(NSCoder*)decoder;

These messages are sent to an object that is about to be encoded or decoded (respectively) by an NSCoder object. As an example, say we have the following class:

@interface CustomObject : NSObject <NSCoding>
{
    NSArray *someArray;
    NSInteger someInteger;
    BOOL someBool;
}
// Method definitions here
@end

When archiving a CustomObject, we'd like to save the values of all of its instance variables. To do this, we can add implementations of the NSCoding methods, like so:

@implementation CustomObject
 
// Other method implementations here
 
- (void) encodeWithCoder:(NSCoder*)encoder {
    // If parent class also adopts NSCoding, include a call to
    // [super encodeWithCoder:encoder] as the first statement.
 
    [encoder encodeObject:someArray forKey:@"someArray"];
    [encoder encodeInteger:someInteger forKey:@"someInteger"];
    [encoder encodeBool:someBool forKey:@"someBool"];
}
 
- (id) initWithCoder:(NSCoder*)decoder {
    if (self = [super init]) {
      // If parent class also adopts NSCoding, replace [super init]
      // with [super initWithCoder:decoder] to properly initialize.
 
      // NOTE: Decoded objects are auto-released and must be retained
      someArray = [[decoder decodeObjectForKey:@"someArray"] retain];
      someInteger = [decoder decodeIntegerForKey:@"someInteger"];
      someBool = [decoder decodeBoolForKey:@"someBool"];
    }
    return self;
}
 
@end

That's it! Now when we attempt to archive our object, the archiver automatically sends the encodeWithCoder: message to our object, and we encode our data into the encoder. Similarly, when we unarchive our object, the archiver sends the initWithCoder: message to a newly-allocated instance of the class, and the object will come back to us exactly as it was before it was archived. Neat!

For archiving an object, do something like the following:

CustomObject *object; // Assume this exists
NSData *encodedObject = [NSKeyedArchiver archivedDataWithRootObject:object];
// Now do something with your NSData object, such
// as write it to a file or save it to NSUserDefaults

For unarchiving an object, do something like the following:

NSData *encodedObject;
// First retrieve your NSData object by reading it
// from a file or grabbing it from NSUserDefaults
CustomObject *object = [NSKeyedUnarchiver unarchiveObjectWithData:encodedObject];

Yes, it really is that simple! Plus, since NSCoding is part of the Foundation framework, this exact code will work on both the Mac and iPhone platforms.

For examples of implementation, check out the CHDataStructures framework — all of the data structures conform to the NSCoding protocol. (Good examples of this include the CHAbstractBinarySearchTree and CHMutableArrayHeap classes.)

For more information on NSCoding and related classes, check out the Archives and Serializations Programming Guide.

Your rating: None Average: 4.6 (34 votes)

Search

UPDATES

The site has recently been updated. You may notice some of the following issues:

  • Some URLs no longer work. Please use the search box.
  • File uploads should now be working. If you experience problems, please contact us.