NSUserDefaults nil Setting Problem
05/26/2010The iPhone has a handy system Settings app that has a unified location to make changes to different apps on you phone. Within your application, Settings.bundle allows the app to display settings in the iPhone Settings application and NSUserDefaults allows an application to programmatically interact with the phone’s default system. When changing a value in the Settings app it will be updated in the phone’s default system so you can retrieve these settings programmatically within your application.
The problem is if your application settings are never opened in the Settings app, when using NSUserDefaults to retrieve setting values within your application, they will be nil even if a DefaultValue is set in your settings bundle. The reason is the settings bundle and the shared NSUserDefaults object are not one in the same. NSUserDefaults needs to be populated with data either through the iPhone Settings app or programmatically in your application. There are few solutions to this floating around the web to initialize the default values but I didn’t find any that I really liked.
Below is a pretty simple method that I call in the application:didFinishLaunchingWithOptions: method of my app delegate. What it does is grab the settings from the settings bundle, and if any item value is nil it will update the value of that item with the specified DefaultValue (if there is one). This ensures that all values that need a default value will have that default value set in the NSUserDefaults shared defaults object. For more information check out the documentation for Settings Application Schema Reference and NSUserDefaults Class Reference.
//get the plist location from the settings bundle
NSString *settingsPath = [[[NSBundle mainBundle] bundlePath] stringByAppendingPathComponent:@"Settings.bundle"];
NSString *plistPath = [settingsPath stringByAppendingPathComponent:@"Root.plist"];
//get the preference specifiers array which contains the settings
NSDictionary *settingsDictionary = [NSDictionary dictionaryWithContentsOfFile:plistPath];
NSArray *preferencesArray = [settingsDictionary objectForKey:@"PreferenceSpecifiers"];
//use the shared defaults object
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
//for each preference item, set its default if there is no value set
for(NSDictionary *item in preferencesArray) {
//get the item key, if there is no key then we can skip it
NSString *key = [item objectForKey:@"Key"];
if (key) {
//check to see if the value and default value are set
//if a default value exists and the value is not set, use the default
id value = [defaults objectForKey:key];
id defaultValue = [item objectForKey:@"DefaultValue"];
if(defaultValue && !value) {
[defaults setObject:defaultValue forKey:key];
}
}
}
//write the changes to disk
[defaults synchronize];
}

