467

I need to check if an dict has a key or not. How?

Andrew Hoos
  • 1,510
  • 2
  • 15
  • 23
dontWatchMyProfile
  • 45,440
  • 50
  • 177
  • 260
  • 4
    (Just for anyone googling to here. Note that this is a very **old question**. SaintMacintosh answer below is the state of the art, it is five years ahead of this QA. Hope it helps.) – Fattie Apr 16 '14 at 13:15
  • 1
    Actually, Andy Dent's answer also gives the state of the art, and more context. And it did this earlier than SaintMacintosh. Do yourself a favor an scroll down a little more. – Peter Kämpf Apr 27 '14 at 08:35
  • 1
    He uses: keysByName[test] != nil the != nil check is redundant and IMHO less readable. I just wanted to share the TL;DR version for people looking the syntax. – Andrew Hoos Jul 30 '14 at 20:17
  • I agree with @SaintMacintosh. his answer is much more succinct. – SAS Jan 29 '15 at 20:56
  • If you wish to check if the `NSDictionary` contains any key (non-specific) you should use `[dictionary allKeys].count == 0` If the `count` is `0` there are no keys in the `NSDictionary`. – Aleksander Azizi Nov 10 '15 at 08:38

16 Answers16

781

objectForKey will return nil if a key doesn't exist.

s4y
  • 50,525
  • 12
  • 70
  • 98
Adirael
  • 9,398
  • 2
  • 22
  • 15
  • 29
    And what if the key does exist, but it's corresponding value is nil? – Fyodor Soikin May 06 '10 at 21:30
  • 234
    That's not possible. You can't add nil to a NSDictionary. You would have to use `[NSNull null]` instead. – Ole Begemann May 06 '10 at 21:39
  • 10
    @fyodor an nsdictionay will throw an NSInvalidArgumentException if you attempt to insert a nil value, so there should never be a case where a key exists, but the corresponding value is nil. – Brad The App Guy May 06 '10 at 22:50
  • 3
    Don't you want to use valueForKey, as that would call objectForKey if necessary? – Raffi Khatchadourian Dec 21 '11 at 00:39
  • 7
    You absolutely do NOT NEVER EVER want to use valueForKey for a JSON dictionary. That's because JSON can contain _any_ string as a key. For example, if it contains "@count" as a key, then objectForKey:@"@count" will give the correct value, but valueForKey:@"@count" will give the number of key/value pairs. – gnasher729 Apr 04 '14 at 18:16
  • To explain again, **IF THERE IS A KEY**, say "keyName", and the value of that key happens to be [NSNull null] (or indeed anything else) .. then ........... **THE KEY DOES EXIST**. The question is how to tell if the KEY EXISTS. If the "KEY EXISTS" and the value is nil {which is not possible anyway in json}, then the "key exists". – Fattie Apr 16 '14 at 13:17
  • @JoeBlow the part you're misunderstanding is that [NSNull null] is not the same as nil. You cannot add nil to a dictionary, but you can add [NSNull null]. – korbonix Oct 03 '14 at 16:34
  • Is this the same as using `dictionary[key]`? – Ky - May 15 '15 at 18:20
  • 1
    @BenLeggiero `dictionary[key]` is the Objective-C modern syntax for `[dictionary objectForKey:key]`this also helps to avoid using wrong methods for this purpose such as `valueForKey` (which is for KVC and is out of the scope of this question). – tomacco Nov 09 '18 at 19:31
164
if ([[dictionary allKeys] containsObject:key]) {
    // contains key
    /* Don't use this solution. Look for more details in comments. */
}

or

if ([dictionary objectForKey:key]) {
    // contains object
}
Aleksejs Mjaliks
  • 8,647
  • 6
  • 38
  • 44
  • 104
    Example one in this answer is slow. – James Van Boxtel Jun 23 '11 at 17:31
  • 8
    read: example one in this answer should be considered illegal (O(n) instead of O(1)) – Hertzel Guinness Nov 28 '13 at 12:45
  • 5
    performance is very relevant. It may be very true that this exact line is irrelevant, but if it going to be repeated n times then all of sudden instead of it taking n time its taking n*m and you can't figure out why your program is slow. Almost everything is fast once or in small cases. But as programs grow using the wrong data structure (like array instead of dict in the first example) will end up costing you big. – Andrew Hoos May 08 '14 at 07:27
  • 2
    Checking a dictionary(or set) for the existence of a key is expected O(1) with a worst case of O(n). Not O(log(n)). Apple's documentation clearly explains this. – Andrew Hoos Aug 12 '14 at 15:58
  • @JoeBlow _“animate the 3D Mecanim dots”_ It sounds like you're confusing Cocoa Touch/Objective-C with Unity Engine/C#. It's true that the Unity Engine is terribly inefficient on the platforms it runs on.  However, it's not at all true that Objective-C/Swift applications are inherently inefficient, nor that most seasoned iOS developers aren't actively cognizant of the efficiency of their code. As for _“only relevant to the (4 living) performance programmers”_ — you're clearly not a game developer. Great graphics & gameplay at 60FPS w/o killing the battery is a continual challenge. – Slipp D. Thompson Nov 05 '16 at 23:17
  • Does [dictionary allKeys] return a Set like data structure or an Array like data structure? A Set should be O(1) query and an Array should be O(n) query. – wz366 Mar 07 '18 at 19:37
100

More recent versions of Objective-C and Clang have a modern syntax for this:

if (myDictionary[myKey]) {

}

You do not have to check for equality with nil, because only non-nil Objective-C objects can be stored in dictionaries(or arrays). And all Objective-C objects are truthy values. Even @NO, @0, and [NSNull null] evaluate as true.

Edit: Swift is now a thing.

For Swift you would try something like the following

if let value = myDictionary[myKey] {

}

This syntax will only execute the if block if myKey is in the dict and if it is then the value is stored in the value variable. Note that this works for even falsey values like 0.

Andrew Hoos
  • 1,510
  • 2
  • 15
  • 23
  • Thanks for this! I am just curious, but I can't find this behavior documented in the objective-c class reference https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSDictionary_Class/Reference/Reference.html#//apple_ref/occ/instm/NSDictionary/ AM I just blind? – irh Aug 07 '14 at 14:36
  • 2
    No you are not blind. It is not emphasized. But visible [here](http://clang.llvm.org/docs/ObjectiveCLiterals.html)(clang) and [here](https://developer.apple.com/library/ios/releasenotes/ObjectiveC/ModernizationObjC/AdoptingModernObjective-C/AdoptingModernObjective-C.html)(modern objc: very bottom) and [here](https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/ProgrammingWithObjectiveC/FoundationTypesandCollections/FoundationTypesandCollections.html)(collections guide: search dictionary) – Andrew Hoos Aug 07 '14 at 18:49
22
if ([mydict objectForKey:@"mykey"]) {
    // key exists.
}
else
{
    // ...
}
ChristopheD
  • 112,638
  • 29
  • 165
  • 179
9

When using JSON dictionaries:

#define isNull(value) value == nil || [value isKindOfClass:[NSNull class]]

if( isNull( dict[@"my_key"] ) )
{
    // do stuff
}
Ratata Tata
  • 2,781
  • 1
  • 34
  • 49
8

I like Fernandes' answer even though you ask for the obj twice.

This should also do (more or less the same as Martin's A).

id obj;

if ((obj=[dict objectForKey:@"blah"])) {
   // use obj
} else {
   // Do something else like creating the obj and add the kv pair to the dict
}

Martin's and this answer both work on iPad2 iOS 5.0.1 9A405

q231950
  • 81
  • 1
  • 3
5

Yes. This kind of errors are very common and lead to app crash. So I use to add NSDictionary in each project as below:

//.h file code :

@interface NSDictionary (AppDictionary)

- (id)objectForKeyNotNull : (id)key;

@end

//.m file code is as below

#import "NSDictionary+WKDictionary.h"

@implementation NSDictionary (WKDictionary)

 - (id)objectForKeyNotNull:(id)key {

    id object = [self objectForKey:key];
    if (object == [NSNull null])
     return nil;

    return object;
 }

@end

In code you can use as below:

NSStrting *testString = [dict objectForKeyNotNull:@"blah"];
pkamb
  • 33,281
  • 23
  • 160
  • 191
torap
  • 656
  • 6
  • 15
5

One very nasty gotcha which just wasted a bit of my time debugging - you may find yourself prompted by auto-complete to try using doesContain which seems to work.

Except, doesContain uses an id comparison instead of the hash comparison used by objectForKey so if you have a dictionary with string keys it will return NO to a doesContain.

NSMutableDictionary* keysByName = [[NSMutableDictionary alloc] init];
keysByName[@"fred"] = @1;
NSString* test = @"fred";

if ([keysByName objectForKey:test] != nil)
    NSLog(@"\nit works for key lookups");  // OK
else
    NSLog(@"\nsod it");

if (keysByName[test] != nil)
    NSLog(@"\nit works for key lookups using indexed syntax");  // OK
else
    NSLog(@"\nsod it");

if ([keysByName doesContain:@"fred"])
    NSLog(@"\n doesContain works literally");
else
    NSLog(@"\nsod it");  // this one fails because of id comparison used by doesContain
P.J.Radadiya
  • 1,493
  • 1
  • 12
  • 21
Andy Dent
  • 17,578
  • 6
  • 88
  • 115
5

Using Swift, it would be:

if myDic[KEY] != nil {
    // key exists
}
pkamb
  • 33,281
  • 23
  • 160
  • 191
rsc
  • 10,348
  • 5
  • 39
  • 36
3

For checking existence of key in NSDictionary:

if([dictionary objectForKey:@"Replace your key here"] != nil)
    NSLog(@"Key Exists");
else
    NSLog(@"Key not Exists");
Aamir
  • 16,329
  • 10
  • 59
  • 65
  • 2
    This is really just a repeat of [this existing answer](https://stackoverflow.com/a/2784664). – Pang Mar 28 '18 at 07:40
3

Because nil cannot be stored in Foundation data structures NSNull is sometimes to represent a nil. Because NSNull is a singleton object you can check to see if NSNull is the value stored in dictionary by using direct pointer comparison:

if ((NSNull *)[user objectForKey:@"myKey"] == [NSNull null]) { }
Andrew Hoos
  • 1,510
  • 2
  • 15
  • 23
Fernandes
  • 216
  • 3
  • 8
  • 1
    Did not work out when I used it with NSMutableArray as object for my key. – pa12 Dec 19 '12 at 23:05
  • 4
    Why on earth did this get upvoted? It's just plain wrong. This check will return true if the singleton `NSNull` instance has been stored in the dictionary as the value for key `@"myKey"`. That's a totally different thing to the key `@"myKey"` not being in the dictionary - indeed the two are mutually exclusive. – Mark Amery Oct 29 '13 at 11:40
  • Since this still has five votes while being totally wrong, I can only repeat what Mark says: This code tests whether the dictionary contains a key with a null value, which is totally different from not containing the key at all. – gnasher729 Apr 04 '14 at 18:19
  • It's "completely wrong, but points to interesting information" – Fattie Apr 16 '14 at 13:05
  • This answer has been edited to clarify what it does do (check for NSNull in a dict) and what it does not do(check for a value in a dict) – Andrew Hoos Jun 22 '16 at 20:59
2

Solution for swift 4.2

So, if you just want to answer the question whether the dictionary contains the key, ask:

let keyExists = dict[key] != nil

If you want the value and you know the dictionary contains the key, say:

let val = dict[key]!

But if, as usually happens, you don't know it contains the key - you want to fetch it and use it, but only if it exists - then use something like if let:

if let val = dict[key] {
    // now val is not nil and the Optional has been unwrapped, so use it
}
Enea Dume
  • 3,014
  • 3
  • 21
  • 36
1

As Adirael suggested objectForKey to check key existance but When you call objectForKeyin nullable dictionary, app gets crashed so I fixed this from following way.

- (instancetype)initWithDictionary:(NSDictionary*)dictionary {
id object = dictionary;

if (dictionary && (object != [NSNull null])) {
    self.name = [dictionary objectForKey:@"name"];
    self.age = [dictionary objectForKey:@"age"];
}
return self;

}

Aleem
  • 3,173
  • 5
  • 33
  • 71
1

I'd suggest you store the result of the lookup in a temp variable, test if the temp variable is nil and then use it. That way you don't look the same object up twice:

id obj = [dict objectForKey:@"blah"];

if (obj) {
   // use obj
} else {
   // Do something else
}
Martin
  • 231
  • 2
  • 4
0
if ([MyDictionary objectForKey:MyKey]) {
      // "Key Exist"
} 
S1LENT WARRIOR
  • 11,704
  • 4
  • 46
  • 60
saurabh rathod
  • 1,090
  • 7
  • 7
  • 1
    This is really just a repeat of [this existing answer](https://stackoverflow.com/a/2784664). – Pang Mar 28 '18 at 07:41
0
if ( [dictionary[@"data"][@"action"] isKindOfClass:NSNull.class ] ){
   //do something if doesn't exist
}

This is for nested dictionary structure

serkanmalagic
  • 71
  • 2
  • 8