Updating NSUserDefaults from Settings.bundle

Trying to access parameters from Root.plist in your Settings.bundle using NSUserDefaults?  Luckily NSUserDefaults will sync those values for you ... after the user opens the Settings preferences for your app first.  As pointed out here, among a few other spots, that certainly seems like a bug, or at least yet another expectation gap.  I know the first thing I do when I download an app is run over to the Settings to see what goodness I can configure.... Sheesh.

 

So to make it easier for me to not have to check, I blended some of the code from Richard Greene's post above with the example from CocoaDev to give me this nice wrapper:

  1. + (void)saveToUserDefaults:(NSString*)key value:(NSString*)valueString
  2. {
  3. NSUserDefaults *standardUserDefaults = [NSUserDefaults standardUserDefaults];
  4.  
  5. if (standardUserDefaults) {
  6. [standardUserDefaults setObject:valueString forKey:key];
  7. [standardUserDefaults synchronize];
  8. } else {
  9. NSLog(@"Unable to save %@ = %@ to user defaults", key, valueString);
  10. }
  11. }
  12.  
  13. + (NSString*)retrieveFromUserDefaults:(NSString*)key
  14. {
  15. NSUserDefaults *standardUserDefaults = [NSUserDefaults standardUserDefaults];
  16. NSString *val = nil;
  17.  
  18. if (standardUserDefaults)
  19. val = [standardUserDefaults objectForKey:key];
  20.  
  21. // TODO: / apparent Apple bug: if user hasn't opened Settings for this app yet (as if?!), then
  22. // the defaults haven't been copied in yet. So do so here. Adds another null check
  23. // for every retrieve, but should only trip the first time
  24. if (val == nil) {
  25. NSLog(@"user defaults may not have been loaded from Settings.bundle ... doing that now ...");
  26. //Get the bundle path
  27. NSString *bPath = [[NSBundle mainBundle] bundlePath];
  28. NSString *settingsPath = [bPath stringByAppendingPathComponent:@"Settings.bundle"];
  29. NSString *plistFile = [settingsPath stringByAppendingPathComponent:@"Root.plist"];
  30.  
  31. //Get the Preferences Array from the dictionary
  32. NSDictionary *settingsDictionary = [NSDictionary dictionaryWithContentsOfFile:plistFile];
  33. NSArray *preferencesArray = [settingsDictionary objectForKey:@"PreferenceSpecifiers"];
  34.  
  35. //Loop through the array
  36. NSDictionary *item;
  37. for(item in preferencesArray)
  38. {
  39. //Get the key of the item.
  40. NSString *keyValue = [item objectForKey:@"Key"];
  41.  
  42. //Get the default value specified in the plist file.
  43. id defaultValue = [item objectForKey:@"DefaultValue"];
  44.  
  45. if (keyValue && defaultValue) {
  46. [standardUserDefaults setObject:defaultValue forKey:keyValue];
  47. if ([keyValue compare:key] == NSOrderedSame)
  48. val = defaultValue;
  49. }
  50. }
  51. [standardUserDefaults synchronize];
  52. }
  53. return val;
  54. }

Here's how I'm using it, for reference.  This block is in my root controller's viewDidLoad method.  It checks the value of the app's version number as stored in the userDefaults, but compares to a #define var.  Why?  Because apparently once you set a PSTitleValueSpecifier preference, you can't change it by editing the plist in Settings.bundle.  Ugh.

  1. NSString *ver = [UtilityFunctions retrieveFromUserDefaults:@"version_number"];
  2. if ([ver compare:kVersionNumber] != NSOrderedSame) {
  3. ver = kVersionNumber;
  4. [UtilityFunctions saveToUserDefaults:@"version_number" value:kVersionNumber];
  5. }

 

Comments

Post new comment

TEXTAREA ID: edit-comment
  • Web page addresses and e-mail addresses turn into links automatically.
  • Allowed HTML tags: <a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd>
  • Lines and paragraphs break automatically.
  • You can enable syntax highlighting of source code with the following tags: <code>, <blockcode>, <c>, <drupal6>, <java>, <javascript>, <objc>, <perl>, <php>, <python>, <rails>, <ruby>, <sql>, <xmlcode>. Beside the tag style "<foo>" it is also possible to use "[foo]".

More information about formatting options

CAPTCHA
This question is for testing whether you are a human visitor and to prevent automated spam submissions.