33

Using NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];,

I use calls like BOOL boolFromPrefs = [defaults boolForKey:@"theBoolKey"]; To get a saved BOOL value.

If the key is not found, NO is returned (default behaviour of boolForKey).
But... NO can be a saved setting. Same thing for intForKey

So how can I test if a key exists before trying to get its value ?

Oliver
  • 23,072
  • 33
  • 138
  • 230

8 Answers8

64

Do it the right way and register default values.

NSDictionary *userDefaultsDefaults = @{
    @"SomeKey": @NO,
    @"AnotherKey": @"FooBar",
    @"NumberKey": @0,
};
[NSUserDefaults.standardUserDefaults registerDefaults:userDefaultsDefaults];

do this before you use anything from NSUserDefaults. The beginning of application:didFinishLaunchingWithOptions: is a safe place.

You have to register the defaults each time the app launches. NSUserDefaults only stores values that have been explicitly set.

If you use default values you don't have to use a check for a "isFirstLaunch" key, like suggested in other answers.
This will help you when you roll out an update and you want to change the default value for a NSUserDefaults item.

Slipp D. Thompson
  • 33,165
  • 3
  • 43
  • 43
Matthias Bauch
  • 89,811
  • 20
  • 225
  • 247
  • 1
    I do see that as a valuable option but I can also see how not registering defaults can beneficial as well. It gives you ternary logic where you can tell if the user explicitly set it to yes or no or did not set it all. – Joe Mar 22 '11 at 21:18
  • I'm not sure but I think that this way of doing works fine for the first 1.0 version. If you have a big change in your preferences hierarchy later, you will probably need to know what is written and what is not, to redispatch the whole thing. Probably... Or perhaps including a single Prefs version into the file will be enough. I don't know, I'm working on this to prevent some problems in the future with old Preference files. Do you know a good source of reading about this ? – Oliver Mar 23 '11 at 00:41
  • those defaults are not written to NSUserDefaults (that's why you have to register them at each launch), when you want new defaults in a later version just register new defaults. If the user never touched a setting the new defaults are used, if he has changed settings he most likely wants to use his own settings anyway. – Matthias Bauch Mar 23 '11 at 10:29
  • Hello. I tried doing it your way. With some problems savong the default prefs. Could you please take a look at this question ? http://stackoverflow.com/questions/5439328/iphone-registering-default-prefs-then-write-them-to-disk – Oliver Mar 26 '11 at 01:04
  • @MatthiasBauch "You have to register the defaults each time the app launches" ? Why ? I only need to registerDefaults once when app is first launched !! – onmyway133 Nov 07 '13 at 09:15
  • Doesnt this override any user`s custom settings if I set the defaults on every app start again? – 最白目 Sep 29 '15 at 07:16
30

Check if the object exists before conversion to a BOOL.

if ([defaults objectForKey:@"theBoolKey"] != nil) {
    boolFromPrefs = [defaults boolForKey:@"theBoolKey"];
} else {
    boolFromPrefs = DEFAULT_BOOL_VALUE;
}
MarkPowell
  • 16,482
  • 7
  • 61
  • 77
  • @phatmann why is that? afaik, ObjectForKey will return nil if it's not set, 0 if it's false and 1 if it's true. – Pega88 Jun 30 '15 at 19:21
  • @Pega88 I was definitely having problems with this approach in a previous version of iOS, and other folks have noted the same issue. In fact this is why I searched stackoverflow. I don't know if this behavior has changed in the latest OSes and what the exact conditions are for it to happen. – phatmann Jul 27 '15 at 17:58
  • @phatmann i think the reason why it didn't work for u ,it's boolForKey used in your code , not objectForKey . – ximmyxiao Apr 06 '16 at 08:46
24

I did it this way:

NSUserDefaults *prefs = NSUserDefaults.standardUserDefaults;
if ([[prefs dictionaryRepresentation].allKeys containsObject:@"yourKey"]) {
  float yourValue = [prefs floatForKey:@"yourKey"];
}
Slipp D. Thompson
  • 33,165
  • 3
  • 43
  • 43
Tim Autin
  • 6,043
  • 5
  • 46
  • 76
  • This is the best solution due to the fact that the value could EQUAL 0 so evaluating the value returned could be incorrect. – avenged May 30 '13 at 22:39
  • I'm concerned about performance. Will this take time to convert the user defaults to a dictionary each time? – Ky - Sep 06 '16 at 13:00
8

You can test by using objectForKey: and if that is nil then it is not set. All boolForKey does it takes the NSNumber returned if any and returns a BOOL value.

Joe
  • 56,979
  • 9
  • 128
  • 135
  • 3
    Note to MonoTouch users: the `ObjectForKey(key)` method is inaccessible, because it's marked internal. Instead, use the indexer: `NSUserDefaults.StandardUserDefaults[key]`. – Niels van der Rest Aug 02 '11 at 13:17
2

I would recommend setting default values for any key that your application might use. You could do this in the application:didFinishLaunchingWithOptions: method. That way you will know that each value has been set.

Hint, set a key called "defaultsSet" to YES so that you only do this once. Also, remember to call [[NSUserDefaults standardUserDefaults] synchronize] to save the values.

picciano
  • 22,341
  • 9
  • 69
  • 82
  • What do you mean by "set a key called "defaultsSet" to YES so that you only do this once" ? – Oliver Mar 23 '11 at 00:44
  • I suggested that as a way to make sure the defaults only get set once and not overwrite user changes. You could call it anything, it's just is another key set to a known value. – picciano Mar 23 '11 at 16:55
  • I'm sorry, I may be tired, but I still don't understand exactly what you mean. Could you give me an example please ? – Oliver Mar 23 '11 at 23:56
0

Swift Example based on MarkPowell's answer

if (NSUserDefaults.standardUserDefaults().objectForKey("SomeBoolSetting") == nil) {
    NSUserDefaults.standardUserDefaults().setBool(true, forKey: "SomeBoolSetting")
    println("Bool WAS nil")
} else {
    var boolValue:Bool? = NSUserDefaults.standardUserDefaults().boolForKey("SomeBoolSetting")
    println("Bool WAS NOT nil \(boolValue)")
}
Michael
  • 9,639
  • 3
  • 64
  • 69
0

swift version of @Tim Autin 's answer:

if contains(NSUserDefaults.standardUserDefaults().dictionaryRepresentation().keys.array, "chuiser_cook_orders_dirty") {
    println("exist")
} 
Michael Shang
  • 686
  • 8
  • 9
  • The Swift 3 syntax is cleaner still, reducing the conditional to: `UserDefaults.standard.dictionaryRepresentation().keys.index(of: "chuiser_cook_orders_dirty") != nil` – Slipp D. Thompson Oct 29 '16 at 22:12
0

Dont Complicate it :

if([NSUserDefaults.standardUserDefaults  objectForKey:@"yourBoolKey"])
{
  // Object Already Stored in User defaults
}
else
{
   //Object not stored
}
Jeba Moses
  • 809
  • 8
  • 25