views:

3773

answers:

4

I have an iPhone application with a settings.bundle that handles various settings for my application. I can set default values in my root.plist file (using the DefaultValue property), but these only get used the first time the user opens the settings app. Is there any way to get these values written out when your application installs? I know I can just write code that checks for the first launch of my app and then write them out, but then they are in two different places.

Here is an entry from my root.plist as an example:

<dict>
    <key>Type</key>
    <string>PSToggleSwitchSpecifier</string>
    <key>Title</key>
    <string>Open To Top Location</string>
    <key>Key</key>
    <string>open_top_location</string>
    <key>DefaultValue</key>
    <string>YES</string>
    <key>TrueValue</key>
    <string>YES</string>
    <key>FalseValue</key>
    <string>NO</string>
</dict>

The end result should be that if I ask for 'open_to_top_location' I get a YES, instead of it not being there at all until the first time the user opens the Settings app.

Any ideas?

+24  A: 

If I understood you correctly, you want to avoid having default values specified twice (once as "DefaultValue" keys in your Settings.bundle/Root.plist file, and once in your app initialization code) so you do not have to keep them in sync.

Since Settings.bundle is stored within the app bundle itself, you can just read the default values given there. I put together some sample code that looks at the Settings bundle and reads the default values for every key there. Note that this does not write out the default keys; if they don't exist, you'll need to read and register them at every launch (feel free to change this). I've only done some cursory tests, so make sure it works for you in all cases.

- (void)applicationDidFinishLaunching:(UIApplication *)application {    
    NSString *name = [[NSUserDefaults standardUserDefaults] stringForKey:@"name"];
    NSLog(@"name before is %@", name);

    // Note: this will not work for boolean values as noted by bpapa below.
    // If you use booleans, you should use objectForKey above and check for null
    if(!name) {
        [self registerDefaultsFromSettingsBundle];
        name = [[NSUserDefaults standardUserDefaults] stringForKey:@"name"];
    }
    NSLog(@"name after is %@", name);
}

- (void)registerDefaultsFromSettingsBundle {
    NSString *settingsBundle = [[NSBundle mainBundle] pathForResource:@"Settings" ofType:@"bundle"];
    if(!settingsBundle) {
        NSLog(@"Could not find Settings.bundle");
        return;
    }

    NSDictionary *settings = [NSDictionary dictionaryWithContentsOfFile:[settingsBundle stringByAppendingPathComponent:@"Root.plist"]];
    NSArray *preferences = [settings objectForKey:@"PreferenceSpecifiers"];

    NSMutableDictionary *defaultsToRegister = [[NSMutableDictionary alloc] initWithCapacity:[preferences count]];
    for(NSDictionary *prefSpecification in preferences) {
        NSString *key = [prefSpecification objectForKey:@"Key"];
        if(key) {
            [defaultsToRegister setObject:[prefSpecification objectForKey:@"DefaultValue"] forKey:key];
        }
    }

    [[NSUserDefaults standardUserDefaults] registerDefaults:defaultsToRegister];
    [defaultsToRegister release];
}
PCheese
I was hoping for some magic bundle setting that I was missing like "WriteDefaultsOnInstall" but in the absence of that this will do, thanks :)
rustyshelf
That's some great sample code. The sample in AppPrefs is clunky compared to that. Thanks!
bbrown
One thing to note for this solution - it doesn't work if your Default is a boolean, since "if(!name)" returns NO if either the default is set to NO or if it doesn't exist. To get around this, I use objectForKey instead, since that will return 0, 1, or null.
bpapa
I was under the impression that the settings.bundle was read automatically after the App was launched. Looks like this isn't the case. The code above by PCheese solved the problem. Nice looking out!
Jordan
A: 

Thanks for the above! Awesome.

A: 

Thanks a lot! This has been the solution to my current headaches ;p

q231950