【问题标题】:iOS: Why can't I set nil to NSDictionary value?iOS:为什么我不能将 nil 设置为 NSDictionary 值?
【发布时间】:2025-11-21 22:20:02
【问题描述】:

这可能是一个非常基本的问题,但我想知道为什么我不能将 nil 分配为 NSDictionary 值?我的代码中有很多地方都有以下声明。如果[q objectForKey:@"text"] 为 nil,则应用程序崩溃。

NSMutableDictionary *dict = [[NSMutableDictionary alloc] initWithCapacity:2];
[dict setObject:[q objectForKey:@"text"] forKey:@"text"];

在将零分配给字典之前,我必须到处检查零。这是唯一正确的做法吗?我错过了什么明显的东西吗?

if([q objectForKey:@"text"] != nil)
    [dict setObject:[q objectForKey:@"text"] forKey:@"text"];
else
    [dict setObject:@"" forKey:@"text"];

【问题讨论】:

    标签: iphone ios nsdictionary null


    【解决方案1】:

    它想要一个实际的对象...使用NSNull

    [NSNull null];
    

    【讨论】:

    • 这看起来很棒。当我设置 NSNull 时,条件 if([q objectForKey:@"text"] == nil) 将是真的还是我必须使用 if([q objectForKey:@"text"] == NSNull)?谢谢。
    • @AppleDeveloper 这不是真的,你必须检查 [NSNull null]
    • 谢谢@peter,所以我需要使用两种不同的条件? if([q objectForKey:@"text"] == nil) 检查键是否存在, if([q objectForKey:@"text"] == [NSNull null]) 检查键是否为空值?
    • @AppleDeveloper 因为你不能将nil 存储在NSDictionary 中,所以检查它已经过时了,因为它永远不会发生。所以,不,不要检查nil,只检查[NSNull null]
    • @PeterPajchl 如果密钥没有值,它将为零。
    【解决方案2】:

    可以使用 setValue:forKey 设置 nil 值,但它会删除密钥。

    如果您希望能够将密钥设置为nil,您可以使用setValue:forKey:,如果您将其设置为nil,它将删除该密钥(引用以下文档)。注意 Value 而不是 Object。

    setValue:forKey:

    将给定的键值对添加到字典中。

    ...
    
    讨论

    此方法使用setObject:forKey: 向字典添加值和键,除非值是nil,在这种情况下,该方法尝试使用removeObjectForKey: 删除键。

    当您稍后尝试使用 objectForKey: 获取对象时,将其设置为 nil 删除的密钥,您将返回 nil(引用以下文档)。

    返回值:

    与 aKey 关联的值,如果没有与 aKey 关联的值,则为 nil。

    注意:该键实际上不会出现在字典中,因此不会使用allKeys 获取;或被枚举一遍。

    【讨论】:

    • 嗨,David,感谢您提供有用的信息,但我在 Apple 文档中看到您仅将 setValue 用于 KVO 和普通键值对,您应该始终使用 setObject!这不是真的吗?
    • @AppleDeveloper 据我所知,字典有自己的 setValue 实现。 NSMutableDictionary 文档(链接在我的答案中)没有说明不使用它:“setValue:forKey: 将给定的键值对添加到字典中。... 讨论此方法将值和键添加到使用setObject:forKey: 的字典,除非值为零,在这种情况下,该方法会尝试使用removeObjectForKey: 删除键。"
    • 这种方法的一个重要限制是setValue:withKey: 需要一个字符串键。使用其他类型是否安全并不完全清楚,编译器会为此发出警告。我想我会避免它,个人。我认为在NSMutableDictionary 上提供setOrClearObject:forKey: 的类别会是一种更安全的方法。
    【解决方案3】:

    你可以这样设置 nil 对象:

    NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
    
    dictionary[@“key”] = nil;
    

    你注意到了吗?

    NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
    
    /* this statement is safe to execute    */
    
    dictionary[@“key”] = nil;
    
    /* but this statement will crash application    */
    
    [dictionary setObject:nil forKey:@"key"];
    

    【讨论】:

      【解决方案4】:

      使用此方法时:

      func setObject(_ anObject: Any, forKey aKey: NSCopying)
      

      参数(根据 Apple 文档):

      一个对象

      如果 anObject 为 nil,则引发 invalidArgumentException。如果你需要 要在字典中表示 nil 值,请使用 NSNull 。

      一键

      如果 aKey 为 nil,则引发 invalidArgumentException。

      【讨论】:

        【解决方案5】:

        我的朋友使用 nil 作为标记是糟糕编程的标志。 nil 保留用于某些不同的目的。

        if([q objectForKey:@"text"] != nil) [dict setObject:[q objectForKey:@"text"] forKey:@"text"]; 别的 [dict removeObjectforKey:@"text"]; // 如果 key 不存在,这将不做任何事情。

        //默认情况下,所有键的值都是 nil 并且您正在尝试覆盖此行为。 违反语言规则总是会给你带来麻烦。

        检查只是使用

        if([dict objectforKey:@"text"] !=nil){} // 这将起作用,因为默认值为 nil 本身

        【讨论】:

        • 我知道,但是我必须这样做才能为键设置默认值!你可以只创建键而不分配值吗?
        • @AppleDeveloper 请解释一下没有值的键会获得什么...
        • 短答案是 no,长答案是 Nooooooooooooooo。
        • @DavidRönnqvist 抱歉,我知道这是不可能的,但我有点讽刺!我正在构建 100 个键值对,其中一些具有值,而另一些缺失,将由用户填充。我正在生成动态 UI 控件,因此如果特定键没有答案/默认值,我需要存储该键以供将来参考并稍后分配值。
        • @AppleDeveloper 我们都在暗示你有一个错误的设计。当你拥有两者时插入键值(这也将节省你的记忆)。我不知道你的上下文是什么,但你总能找到比插入 nil 值更好的解决方案。