I Have a small problem with NSCoding and NSKeyedArchiver when persisting my App Settings class and was hoping someone could spot an issue if it's my code, I am relatively new to Obj-C but have plenty of coding experience in numerous languages so the code seems ok to me but...
I have an instance class to hold my app Settings, the class itself is a retained property of the main App Delegate, this is created via a
@interface AppDelegate : NSObject <UIApplicationDelegate> {
Settings *settings;
[...]
}
@property (nonatomic, retain) Settings *settings;
[...]
This is created in the applicationDidFinishLaunching event as:
settings = [Settings LoadSettings];
If I comment out the above line then the app works fine every time, however if I pull the oject back from persisted settings using NSCoder and NSKeyedUnarchiver, the SIGARBT error is thrown as a NSCFString selector is being sent for what is encoded as a boolean property? The Settings Class is defined as an NSObject which implements the protocol.
@interface Settings : NSObject <NSCoding>
As I say, creating an instance of the settings class is fine, there is no issue, saving it seems OK as well as checking the returning class from the LoadSettings method shows the right values, only after exiting the method does the expected bool value seem to be getting sent to the load method as an NSCFString
- (id)initWithCoder:(NSCoder *)decoder {
if (self = [super init]) {
[...]
self.animateMenus = [decoder decodeBoolForKey:@"animateMenus"];
}
return self;
}
- (void)encodeWithCoder:(NSCoder *)encoder {
[...]
[encoder encodeBool:animateMenus forKey:@"animateMenus"];
}
Once the settings have been loaded the property in question is used like this:
SettingsViewController *settingsView = [[SettingsViewController alloc] initWithNibName:@"SettingsView" bundle:nil];
[self presentModalViewController:settingsView animated:[AppDelegate instance].settings.animateMenus];
[settingsView release];
**The animateMenus member of the settings class will now throw the following:
-[NSCFString animateMenus]: unrecognized selector sent to instance 0xc712570 2010-10-15 11:12:51.828 App[900:207] * Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NSCFString animateMenus]: unrecognized selector sent to instance 0xc712570'
Whereas, taking the 'settings = [Settings LoadSettings];' call out of the app start-up removes the issue (but then always uses the app defaults)?
Load and Save Methods:
+ (Settings*) LoadSettings {
Settings *s = nil;
@try {
NSData *data = [[NSUserDefaults standardUserDefaults] objectForKey:@"settings"];
if (data == nil) {
s = [[Settings alloc] init];
[s Initialise];
[s SaveSettings];
}
else
s = (Settings*)[NSKeyedUnarchiver unarchiveObjectWithData:data];
}
@catch (NSException * e) {
NSLog(@"Error Loading Settings\n%@", [e reason]);
}
@finally {
return s;
}
}
// Saves the settings dictionary to the user's device documents folder..
- (void) SaveSettings {
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:self];
[[NSUserDefaults standardUserDefaults] setObject:data forKey:@"settings"];
}
Load is a static method all other members of Settings are instance.