如何检查NSDictionary或NSMutableDictionary是否包含密钥?


456

我需要检查字典是否有键。怎么样?


4
(仅对任何使用Google搜索的人来说。注意,这是一个非常老的问题。下面的SaintMacintosh回答是最先进的技术,它比QA提前了五年。希望对您有所帮助。)
Fattie

1
实际上,安迪·登特(Andy Dent)的回答还提供了最新技术以及更多背景信息。它比SaintMacintosh更早地完成了此任务。帮自己一个忙,向下滚动一点。
彼得·坎普夫(PeterKämpf)2014年

1
他使用:keysByName [test]!= nil!= nil检查是多余的,恕我直言,可读性较差。我只想为看语法的人分享TL; DR版本。
Andrew Hoos 2014年

我同意@SaintMacintosh。他的回答更加简洁。
史蒂夫·施瓦茨

如果您希望检查,如果其中NSDictionary包含任何键(非特定键),则应使用[dictionary allKeys].count == 0如果,count0中没有键NSDictionary
Aleksander Azizi

Answers:


768

objectForKey 如果键不存在,将返回nil。


29
如果该键确实存在,但其对应的值为nil呢?
Fyodor Soikin,2010年

232
那不可能 您不能在NSDictionary中添加nil。您将不得不使用[NSNull null]
Ole Begemann,2010年

10
如果尝试插入nil值,则nsdictionay会@fyodor抛出NSInvalidArgumentException,因此永远不会存在键存在的情况,但是对应的值为nil。
Brad The App Guy 2010年

3
您是否不想使用valueForKey,因为如果需要,它将调用objectForKey?
拉菲·哈查杜安

6
您绝对永远都不想将valueForKey用于JSON字典。这是因为JSON可以包含任何字符串作为键。例如,如果它包含“ @count”作为键,则objectForKey:@“ @ count”将给出正确的值,但是valueForKey:@“ @ count”将给出键/值对的数量。
gnasher729 2014年

162
if ([[dictionary allKeys] containsObject:key]) {
    // contains key
}

要么

if ([dictionary objectForKey:key]) {
    // contains object
}

100
此答案中的示例一很慢。
James Van Boxtel

5
阅读:此答案中的一个示例应被视为非法(O(n)而不是O(1))
Hertzel Guinness

5
性能非常重要。确切的说这行是无关紧要的,但是如果要重复执行n次,则会突然出现,而不是花费n倍的时间消耗n * m,您就无法弄清楚程序为什么变慢了。一次或在很小的情况下,几乎所有事情都很快。但是随着程序使用错误的数据结构(如第一个示例中的array而不是dict),最终将使您付出巨大的代价。
2014年

2
期望在字典(或集合)中检查键的存在,O(1)的情况最糟的是O(n)。不是O(log(n))。苹果的文档清楚地解释了这一点。
Andrew Hoos 2014年

@JoeBlow “为3D Mecanim点设置动画”听起来好像您将Cocoa Touch / Objective-C与Unity Engine / C#混淆了。的确,Unity Engine在其运行的平台上效率极低。但是,Objective-C / Swift应用程序天生就没有效率,这也不是真的,也不是大多数经验丰富的iOS开发人员都没有积极意识到其代码的效率。至于“仅与(四个活着的)性能程序员有关”,您显然不是游戏开发人员。出色的图形和60 fps的游戏玩法,而又不浪费电池,这是一个持续的挑战。
斯利普·汤普森

98

较新版本的Objective-C和Clang具有现代语法:

if (myDictionary[myKey]) {

}

您不必检查是否与nil相等,因为只有非nil的Objective-C对象可以存储在字典(或数组)中。而且所有Objective-C对象都是真实值。甚至@NO,,@0并且[NSNull null]评估为true。

编辑:Swift现在是一回事。

对于Swift,您可以尝试以下操作

if let value = myDictionary[myKey] {

}

如果myKey在dict中,如果myKey存放在value变量中,则此语法仅执行if块。请注意,这适用于虚假的值,例如0。


谢谢你!我只是很好奇,但是我找不到在Objective-C类参考developer.apple.com/library/mac/documentation/Cocoa/Reference/中记录的这种行为。 我只是瞎了吗?
irh 2014年

2
不,你不是瞎子。不强调。但是这里(c )和这里(现代objc:非常底部)以及这里(集合指南:搜索词典)可见
Andrew


9

使用JSON字典时:

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

if( isNull( dict[@"my_key"] ) )
{
    // do stuff
}

8

即使您两次请求obj,我也喜欢Fernandes的回答。

这也应该做(或多或少与马丁的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
}

马丁和这个答案都适用于iPad2 iOS 5.0.1 9A405


5

一个非常讨厌的陷阱只是浪费了我一些时间进行调试-您可能会发现自己被自动完成提示,尝试使用doesContain似乎可行的方法。

除非doesContain使用id比较而不是使用的哈希比较,objectForKey所以如果您有带有字符串键的字典,它将返回NO 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

5

使用Swift,它将是:

if myDic[KEY] != nil {
    // key exists
}

5

是。这种错误非常常见,并会导致应用崩溃。所以我经常在每个项目中添加NSDictionary,如下所示:

//.h文件代码:

@interface NSDictionary (AppDictionary)

- (id)objectForKeyNotNull : (id)key;

@end

//.m文件代码如下

#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

在代码中,您可以使用以下代码:

NSStrting *testString = [dict objectForKeyNotNull:@"blah"];

3

要检查NSDictionary中密钥的存在:

if([dictionary objectForKey:@"Replace your key here"] != nil)
    NSLog(@"Key Exists");
else
    NSLog(@"Key not Exists");

1
这实际上只是现有答案的重复。

3

因为nil无法存储在Foundation中,所以数据结构NSNull有时代表nil。因为NSNull是单例对象,所以您可以NSNull使用直接指针比较来检查是否存储在字典中的值:

if ((NSNull *)[user objectForKey:@"myKey"] == [NSNull null]) { }

1
当我将其与NSMutableArray用作密钥对象时,效果不佳。
pa12 2012年

4
为什么这在地球上遭到反对?这是完全错误的。如果单例NSNull实例已作为key的值存储在字典中,则此检查将返回true @"myKey"。这@"myKey"与字典中没有的键是完全不同的-确实两者是互斥的。
马克·阿默里

由于这完全有错,但仍然有5票,所以​​我只能重复Mark所说的:该代码测试字典是否包含具有空值的键,这与根本不包含键完全不同。
gnasher729 2014年

这是“完全错误,但指向有趣的信息”
Fattie 2014年

已编辑此答案,以弄清楚它的作用(在dict中检查NSNull)和不做什么(在dict中检查值)
Andrew Hoos16年

2

快速4.2解决方案

因此,如果您只想回答字典是否包含密钥的问题,请询问:

let keyExists = dict[key] != nil

如果您需要该值并且知道字典包含键,请说:

let val = dict[key]!

但是,如果像通常发生的那样,您不知道它包含密钥-您想获取它并使用它,但只有在它存在的情况下-才可以使用if let

if let val = dict[key] {
    // now val is not nil and the Optional has been unwrapped, so use it
}

1

我建议您将查找结果存储在temp变量中,测试temp变量是否为nil,然后使用它。这样,您就不会两次看到相同的对象:

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

if (obj) {
   // use obj
} else {
   // Do something else
}

1

正如Adirael建议objectForKey检查键是否存在,但是当您objectForKey在可为空的字典中调用时,应用程序崩溃了,因此我通过以下方式修复了此问题。

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

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

}


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.