【问题标题】:How to check if an NSDictionary or NSMutableDictionary contains a key?如何检查 NSDictionary 或 NSMutableDictionary 是否包含密钥?
【发布时间】:2011-02-16 14:21:53
【问题描述】:

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

【问题讨论】:

  • (仅供谷歌搜索到这里的任何人使用。请注意,这是一个非常老问题。下面的 SaintMacintosh 答案是最先进的,比这个 QA 提前了五年. 希望对您有所帮助。)
  • 实际上,Andy Dent 的回答也提供了最先进的技术和更多背景信息。它比 SaintMacintosh 更早地做到了这一点。帮自己一个忙,向下滚动一点。
  • 他使用:keysByName[test] != nil != nil 检查是多余的,恕我直言,可读性较差。我只是想与寻找语法的人分享 TL;DR 版本。
  • 我同意@SaintMacintosh。他的回答要简洁得多。
  • 如果您想检查NSDictionary 是否包含任何键(非特定),您应该使用[dictionary allKeys].count == 0 如果count0,则NSDictionary 中没有键.

标签: objective-c foundation


【解决方案1】:

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

【讨论】:

  • 如果key确实存在,但对应的值为nil怎么办?
  • 这是不可能的。您不能将 nil 添加到 NSDictionary。您必须改用[NSNull null]
  • @fyodor 如果您尝试插入 nil 值,nsdictionay 将抛出 NSInvalidArgumentException,因此永远不会出现键存在但对应值为 nil 的情况。
  • 您不想使用 valueForKey,因为必要时会调用 objectForKey?
  • 您绝对不会想将 valueForKey 用于 JSON 字典。这是因为 JSON 可以包含 any 字符串作为键。例如,如果它包含“@count”作为键,那么 objectForKey:@"@count" 将给出正确的值,但 valueForKey:@"@count" 将给出键/值对的数量。
【解决方案2】:
if ([[dictionary allKeys] containsObject:key]) {
    // contains key
}

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

【讨论】:

  • 这个答案中的例子很慢。
  • 阅读:此答案中的示例应被视为非法(O(n) 而不是 O(1))
  • 性能非常相关。这条确切的行是无关紧要的,这可能是非常正确的,但如果它要重复 n 次,那么突然而不是花费 n 时间它花费 n*m 并且你无法弄清楚为什么你的程序很慢。几乎所有东西都快速一次或在小情况下。但是随着程序使用错误的数据结构(例如第一个示例中的数组而不是 dict)增长,最终会让您付出巨大的代价。
  • 检查一个字典(或集合)是否存在一个键需要 O(1),最坏的情况是 O(n)。不是 O(log(n))。 Apple 的文档清楚地解释了这一点。
  • @JoeBlow “为 3D Mecanim 点设置动画” 听起来您将 Cocoa Touch/Objective-C 与 Unity Engine/C# 混淆了。确实,Unity 引擎在其运行的平台上效率极低。然而,Objective-C/Swift 应用程序本身就不是低效的,也不是大多数经验丰富的 iOS 开发人员没有积极认识到他们代码的效率。至于“只与(4 个在世的)性能程序员有关”——你显然不是游戏开发者。在不消耗电池的情况下以 60FPS 的出色图形和游戏玩法是一项持续的挑战。
【解决方案3】:

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

if (myDictionary[myKey]) {

}

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

编辑:Swift 现在是一个东西。

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

if let value = myDictionary[myKey] {

}

如果 myKey 在 dict 中,则此语法只会执行 if 块,如果是,则值存储在 value 变量中。请注意,这甚至适用于像 0 这样的虚假值。

【讨论】:

【解决方案4】:
if ([mydict objectForKey:@"mykey"]) {
    // key exists.
}
else
{
    // ...
}

【讨论】:

    【解决方案5】:

    使用 JSON 字典时:

    #define isNull(value) value == nil || [value isKindOfClass:[NSNull class]]
    
    if( isNull( dict[@"my_key"] ) )
    {
        // do stuff
    }
    

    【讨论】:

      【解决方案6】:

      我喜欢费尔南德斯的回答,即使您两次要求 obj。

      这也应该可以(与 Martin 的 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 和这个答案都适用于 iPad2 iOS 5.0.1 9A405

      【讨论】:

        【解决方案7】:

        一个非常讨厌的问题,只是浪费了我一点时间调试 - 你可能会发现自动完成提示你尝试使用 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
        

        【讨论】:

          【解决方案8】:

          使用 Swift,它将是:

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

          【讨论】:

            【解决方案9】:

            是的。这种错误很常见,会导致应用程序崩溃。所以我使用在每个项目中添加 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"];
            

            【讨论】:

              【解决方案10】:

              用于检查 NSDictionary 中是否存在键:

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

              【讨论】:

              【解决方案11】:

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

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

              【讨论】:

              • 当我将它与 NSMutableArray 一起用作我的密钥的对象时没有成功。
              • 这到底为什么会得到支持?这完全是错误的。如果单例 NSNull 实例已作为键 @"myKey" 的值存储在字典中,则此检查将返回 true。这与键 @"myKey" 不在字典中是完全不同的 - 实际上两者是相互排斥的。
              • 由于这仍然有五票而完全错误,我只能重复马克所说的:这段代码测试字典是否包含具有空值的键,这与不包含键完全不同完全没有。
              • “完全错误,但指向有趣的信息”
              • 这个答案已经过编辑,以阐明它做了什么(检查字典中的 NSNull)和不做什么(检查字典中的值)
              【解决方案12】:

              swift 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
              }
              

              【讨论】:

                【解决方案13】:

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

                id obj = [dict objectForKey:@"blah"];
                
                if (obj) {
                   // use obj
                } else {
                   // Do something else
                }
                

                【讨论】:

                  【解决方案14】:
                  if ([MyDictionary objectForKey:MyKey]) {
                        // "Key Exist"
                  } 
                  

                  【讨论】:

                  【解决方案15】:

                  正如 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;
                  

                  }

                  【讨论】:

                    【解决方案16】:
                    if ( [dictionary[@"data"][@"action"] isKindOfClass:NSNull.class ] ){
                       //do something if doesn't exist
                    }
                    

                    这是用于嵌套字典结构

                    【讨论】:

                      猜你喜欢
                      • 1970-01-01
                      • 2011-06-05
                      • 1970-01-01
                      • 2012-11-24
                      • 1970-01-01
                      • 1970-01-01
                      • 2018-06-09
                      • 2011-01-12
                      • 2013-07-03
                      相关资源
                      最近更新 更多