Archiving NSManagedObject with NSCoding
Posted on
Several of the apps I have been working on lately have been using Core Data. Core Data is pretty sweet. So far, I really like it.
I needed to persist an array of NSManagedObjects to NSUserDefaults to persist the state of the application between launches. Obviously, I could have done this with another attribute on the Core Data entity, but this approach seemed a lot simpler. I was surprised that NSManagedObject didn't conform to NSCoding. I guess that makes sense because if you store any custom types in your entity, it wouldn't know how to archive them. In my case, (and I would assume most others) I didn't want to archive the entire object since it was already store in Core Data. I just needed to store the object ID.
This was actually really easy. See:
//
// SSManagedObject.h
// Archiving NSManagedObject with NSCoding
//
// Created by Sam Soffes on 2/28/10.
// Copyright 2010 Sam Soffes. All rights reserved.
//
extern NSString *kURIRepresentationKey;
@interface SSManagedObject : NSManagedObject <NSCoding> {
}
@end
//
// SSManagedObject.m
// Archiving NSManagedObject with NSCoding
//
// Created by Sam Soffes on 2/28/10.
// Copyright 2010 Sam Soffes. All rights reserved.
//
#import "SSManagedObject.h"
#import "AppDelegate.h"
NSString *kURIRepresentationKey = @"URIRepresentation";
@implementation SSManagedObject
- (id)initWithCoder:(NSCoder *)decoder {
AppDelegate *appDelegate = [AppDelegate sharedAppDelegate];
NSPersistentStoreCoordinator *psc = [appDelegate persistentStoreCoordinator];
NSManagedObjectContext *context = [appDelegate managedObjectContext];
self = (SSManagedObject *)[[context objectWithID:[psc managedObjectIDForURIRepresentation:(NSURL *)[decoder decodeObjectForKey:kURIRepresentationKey]]] retain];
return self;
}
- (void)encodeWithCoder:(NSCoder *)encoder {
[encoder encodeObject:[[self objectID] URIRepresentation] forKey:kURIRepresentationKey];
}
@end
I always add + (id)sharedAppDelegate
to my application delegate to save some typing:
+ (AppDelegate *)sharedAppDelegate {
return (AppDelegate *)[[UIApplication sharedApplication] delegate];
}
Pretty simple right? Then you can do something like this to archive your objects:
[[[AppDelegate sharedAppDelegate] managedObjectContext] save:nil];
NSData *archivedObjects = [NSKeyedArchiver archivedDataWithRootObject:objects];
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
[userDefaults setObject:archivedObjects forKey:@"someKey"];
[userDefaults synchronize];
Unarchiving is also super easy:
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
NSData *objectsData = [userDefaults objectForKey:@"someKey"];
if ([objectsData length] > 0) {
NSArray *objects = [NSKeyedUnarchiver unarchiveObjectWithData:objectsData]];
}