Update: This works if I call archiveRootObject: from applicationDidFinishLaunching:. If I call it from the init: method of a singleton class, it returns nil.
You must always -retain
an unarchived object: Game *g2 = [[NSKeyedUnarchiver unarchiveObjectWithFile:archivePath] retain];
Does your g2
conform to NSCoding
? Make sure it does, if it doesn't declare <NSCoding>
in the g2
header. In the implementation file define methods -(id)initWithCoder:(NSCoder *)coder
and -(void)encodeWithCoder:(NSCoder *)coder
If you're struggling to get this to work consider archiving and unarchiving a standard NSObject, like an NSString or some such. You probably don't need to archive a whole custom object, maybe just a remaining time number, game location or position or score. In other words, archive and unarchive the bare minimum you need.
I've meet the same trouble in Xcode 4.1 with ARC support:
BOOL isFileExist = [[NSFileManager defaultManager] fileExistsAtPath:filePath];
NSAssert(isFileExist, @"filePath does not exist");
NSKeyedUnarchiver* coder =
[NSKeyedUnarchiver unarchiveObjectWithFile:filePath]; // nil
NSData* data = [[NSFileManager defaultManager] contentsAtPath:filePath];
coder = [NSKeyedUnarchiver unarchiveObjectWithData:data]; // nil
coder = [[NSKeyedUnarchiver alloc] initForReadingWithData:data]; // OK!!!
It seems to be a bug in cocoa-touch.
Edit:
It is intended to behave like this and is not a bug. But I agree that the naming easily leads to mistakes.
[[NSKeyedUnarchiver alloc] initForReadingWithData:]
returns a NSKeyedUnarchiver
instance.
[NSKeyedUnarchiver unarchiveObjectWithData:]
returns the root object. It is a conviencen method for:
NSKeyedUnarchiver *coder = [[self alloc] initForReadingWithData:arg2];
id object = [coder decodeObjectForKey:@"root"];