Monday, July 26, 2010

NSKeyedArchiver: Encoding and Decoding for Fun and Profit

More on Serializing and deserializing, which -- if you're ever on a job interview -- is called "archiving and unarchiving." Serialization is a superset, or something... I'm a bit loose with the terminology these days.

What if you want to get a serializable piece and then just reconstruct your object with it yourself? Could you save that piece to disk and recover it and do this too? I needed this for an app I'm doing, so the answer is yes. It works.

Simple object .h



@interface Person : NSObject <NSCoding>{
NSString *name;
}

@property (nonatomic, retain) NSString *name;

and .m



@synthesize name;

- (void)encodeWithCoder:(NSCoder *)aCoder {
[super encodeWithCoder:aCoder];
[aCoder encodeObject:self.name forKey:@"name"];
}
- (id)initWithCoder:(NSCoder *)aDecoder {
    if ((self = [super initWithCoder:aDecoder])) {
self.name = [aDecoder decodeObjectForKey:@"name"];
    }
    return self;
}

and now the code that does everything



Person *person = [[[Person alloc] init] autorelease];
person.name = @"bob";
NSData *dater = [NSKeyedArchiver archivedDataWithRootObject:person];
BOOL result = [NSKeyedArchiver archiveRootObject:dater 
toFile:@"somewhereInAppSandbox"];
NSLog(@"How was saving? %@", result ? @"yes" : @"no" );
dater = [NSKeyedUnarchiver unarchiveObjectWithFile:@"somewhereInAppSandbox"];
person = [NSKeyedUnarchiver unarchiveObjectWithData:dater];
NSLog(@"Are we there? %@", person.name);
Since we call the super methods for both init and encode, this works perfectly well even if the initial serialized object was a NIB.

The point of this entire exercise is to allow you to reuse your encodeWithCoder and initWithCoder methods to, for instance, make deep clones. This is very important because it will keep:
  1. Your code DRY and therefore
  2. You from going insane
Note: The filenames as presented won't work on an iOS device. See my later post here for just the filenames bit.

No comments: