Reputation: 331
EDIT: Code updated to reflect Paul.s's suggestions.
Have been scouring SO for the past week and still cannot get my app to persist the changes to settings from within the app across a shutdown/restart of the app in both Sim and Device.
Trying to use a NSMutableDictionary from a Singleton, but I don't think this is the problem.
a) Set initial default values for the app using registerDefaults in AppDelegate's applicationDidFinishLaunchingWithOptions:
AppManager *global = [AppManager sharedInstance];
// set up the defaults.
global.gWantFoo = YES; // This is a BOOL which relates to a UISwitch
// #define kWantFoo @"gWantFoo"
global.globalSettingsDict = [[NSMutableDictionary alloc]
initWithObjectsAndKeys:
[NSNumber numberWithBool:global.gWantFoo], kWantFoo, nil];
global.globalSettings = [NSUserDefaults standardUserDefaults];
[global.globalSettings registerDefaults:global.globalSettingsDict];
[global.globalSettings synchronize];
b) In the ConfigView where I am able to set the switch, I have the a selector execute the following on a switch change.
self.global.gWantFoo = NOT(self.global.gWantFoo); // #define NOT(a) !(a)
[self.global.globalSettings setBool:self.global.gWantFoo forKey:kWantFoo];
[self.global.globalSettings synchronize];
c) I have a synchronize in applicationDidEnterBackground and friends, and while the switch value does keep the change for the duration of the app instance's life, once I restart, gWantFoo is overwritten with the default of "YES".
Any advice is appreciated. I'm on the verge of defenestrating my ailing macbook pro with a hail of expletives following it closely behind. Ok, i'm calmer for this edit. I feel like gently shaking the macbook pro to demonstrate that i'm less than pleased with NSUserDefaults :-)
Cheers
sc.
Upvotes: 3
Views: 980
Reputation: 38728
So from start to finish this is what you need to do/what should be happening
In application:didFinishLaunchingWithOptions:
one of the first things you do is register defaults like this:
NSDictionary *defaultsDefaults = [[NSDictionary alloc] initWithObjectsAndKeys:[NSNumber numberWithBool:NO] , PSWantFoo, nil];
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults registerDefaults:defaultsDefaults];
Note: PSWantFoo
is defined as NSString * const PSWantFoo = @"PSWantFoo";
so i don't have string literals littered everywhere.
At this point if the app has never been run NSLog(@"%d", [defaults boolForKey:PSWantFoo]);
it will print 0
.
Now when I want to set the value I use something like:
[defaults setBool:YES forKey:PSWantFoo];
[defaults synchronize];
Now when I run NSLog(@"%d", [defaults boolForKey:PSWantFoo]);
it will print 1
.
As for persistance at this point as I have actually set a value a plist is created for me at
<path to app>/Library/Preferences/<bundle identifier>.plist
If you inspect this file you will see something like
<?xml version="1.0" encoding="UTF-8"?>
<DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>PSWantFoo</key>
<true/>
</dict>
</plist>
Now from this point on this value will be read as opposed to the one registered in registerDefaults:
Update
Why have you hardcoded this in this order?
// set up the defaults.
global.gWantFoo = YES; // This is a BOOL which relates to a UISwitch
Why not do it the other way round?
Register defaults with default value YES;
NSDictionary *defaultsDefaults = [[NSDictionary alloc] initWithObjectsAndKeys:
[NSNumber numberWithBool:YES], kWantFoo, nil];
[defaults registerDefaults:defaultsDefaults];
and then after that you get the setting
global.gWantFoo = [defaults boolForKey:kWantFoo];
This way if the app has not yet set the preference the answer will be YES
otherwise it will be what the app has previously set it to.
Upvotes: 3
Reputation: 5038
You should set the flag @"gSettingsAreSet" after defaults values are saved
[[NSUserDefaults standardUserDefaults] setObject:@"YES" forKey:@"gSettingsAreSet"];
[[NSUserDefaults standardUserDefaults] synchronize];
Upvotes: 0