Reputation: 20686
I've got some settings saved in my Settings.bundle, and I try to use them in application:didFinishLaunchingWithOptions
, but on a first run on the simulator accessing objects by key always returns nil
(or 0 in the case of ints). Once I go to the settings screen and then exit, they work fine for every run thereafter.
What's going on? Isn't the point of using default values in the Settings.bundle to be able to use them without requiring the user to enter them first?
Upvotes: 4
Views: 3201
Reputation: 6336
The values in the Settings.bundle are intended for the Settings app to able to fill in default values for your app. They are not used by your own app. But you can set defaults yourself with the registerDefaults: method of NSUserDefaults. This will not actually set them on disk but just give "defaults for the defaults": they are used when no value has been set by the user yet.
Setting registerDefaults: must be done before any use of the default values. The "applicationDidFinishLaunching:" method that others suggested for this, is too late in most cases. By the time "applicationDidFinishLaunching:" is called, your views have already been loaded from the nib files, and their "viewDidLoad:" methods have been called. And they may typically read user defaults.
To guarantee that the defaults are set before first use, I use the following utility class, which loads the values from the Root.plist file and sets them with "registerDefaults:". You use this class to read user defaults instead of "[NSUserDefaults standardUserDefaults]". Use "[Settings get]" instead.
As a bonus, it also contains a registration method for user default change notifications, because I always forget how that is done.
#import "Settings.h"
@implementation Settings
static bool initialized = NO;
+ (void) setDefaults
{
NSString *bundlePath = [[NSBundle mainBundle] bundlePath];
NSString *settingsBundlePath = [bundlePath stringByAppendingPathComponent:@"Settings.bundle"];
NSBundle *settingsBundle = [NSBundle bundleWithPath:settingsBundlePath];
NSString *settingsPath = [settingsBundle pathForResource:@"Root" ofType:@"plist"];
NSDictionary *settingsDict = [NSDictionary dictionaryWithContentsOfFile:settingsPath];
NSArray *prefSpecifierArray = [settingsDict objectForKey:@"PreferenceSpecifiers"];
NSMutableDictionary *appDefaults = [[NSMutableDictionary alloc] init];
for (NSDictionary *prefItem in prefSpecifierArray)
{
NSString *key = [prefItem objectForKey:@"Key"];
if (key != nil) {
id defaultValue = [prefItem objectForKey:@"DefaultValue"];
[appDefaults setObject:defaultValue forKey:key];
}
}
// set them in the standard user defaults
[[NSUserDefaults standardUserDefaults] registerDefaults:appDefaults];
if (![[NSUserDefaults standardUserDefaults] synchronize]) {
NSLog(@"Settings setDefaults: Unsuccessful in writing the default settings");
}
}
+ (NSUserDefaults *)get
{
if (!initialized) {
[Settings setDefaults];
initialized = YES;
}
return [NSUserDefaults standardUserDefaults];
}
+ (void) registerForChange:(id)observer selector:(SEL)method
{
[[NSNotificationCenter defaultCenter] addObserver:observer selector:method name:NSUserDefaultsDidChangeNotification object:nil];
}
+ (void) unregisterForChange:(id)observer
{
[[NSNotificationCenter defaultCenter] removeObserver:observer name:NSUserDefaultsDidChangeNotification object:nil];
}
Upvotes: 2
Reputation: 818
If I got your question right, in your app delegate's - (void)applicationDidFinishLaunching:(UIApplication *)application, set the default values for your settings by calling registerDefaults:dictionaryWithYourDefaultValues on [NSUserDefaults standardUserDefaults]
- (void)applicationDidFinishLaunching:(UIApplication *)application {
NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithInt:3], @"SomeSettingKey",
@"Some string value", @"SomeOtherSettingKey",
nil];
[ud registerDefaults:dict];
}
These values will only by used if those settings haven't been set or changed by previous executions of your application.
Upvotes: 5
Reputation: 33101
Isn't the point of using default values in the Settings.bundle to be able to use them without requiring the user to enter them first?
No. The point of the settings bundle is to give the user a place to edit all 3rd Party app settings in a convenient place. Whether or not this centralization is really a good idea is a User Experience issue that is off topic.
To answer your question, you should detect if it is the first load, then store all your defaults initially.
And while we are on the subject, I would also check out In App Settings Kit as it provides your app with a simple way to display your app settings in both places (in-app and Settings.app) with minimal code.
Upvotes: 2
Reputation: 4719
As coneybeare said "You should detect if it is the first load, then store all your defaults initially."
On applicationDidFinishLaunching try to set default value in your preference.
Here is the sample:
NSUserDefaults *defaults =[NSUserDefaults standardUserDefaults];
if([defaults objectForKey:@"YOUR_KEY"] == nil)
{
[defaults setValue:@"KEY_VALUE" forKey:@"YOUR_KEY"];
}
When application will run second time it will come with KEY_VALUE for YOUR_KEY.
Thanks,
Jim.
Upvotes: 3