【问题标题】:Check if key of NSMutableDictionary is nil检查 NSMutableDictionary 的键是否为 nil
【发布时间】:2016-04-03 11:41:01
【问题描述】:

如果从 Json 数据中得到 NSMutableDictionary

  NSMutableDictionary *returnedDict = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&error];

我知道这个键returnedDict[@"data"][@"weather"][day][@"tides"] 在某些情况下是NSNull。所以我得到-[NSNull objectForKeyedSubscript:]

所以我尝试根据这个答案How to check if an NSDictionary or NSMutableDictionary contains a key?检查它是否为nil。

if (returnedDict[@"data"][@"weather"][day][@"tides"]){ some code }

if (returnedDict[@"data"][@"weather"][day][@"tides"]!=[NSNull null]){ some code}

不避免运行{一些代码}

如何正确检查?

【问题讨论】:

  • 键为空还是值?
  • 一般来说,明智的做法是让 if 子句中的任何内容都计算为真正的 BOOL。使用语言的副作用(在这种情况下'任何非零值都被认为是')不太可取,因为它可能会导致意外的误报(就像你的情况一样),它会使你的代码稍微不太清楚别人和你未来的自己。此外,现在有了 Swift,让它成为一种习惯是很聪明的,因为在 Swift 中,它要求任何 if 子句的计算结果为 Bool。
  • Value 是 NSNull 的一个实例

标签: ios objective-c


【解决方案1】:

所以你的问题是:

您的服务器可能会返回 null 以指示对象不存在。 NSJSONSerialization 会将 null 转换为 NSNull 的实例。从理论上讲,这意味着您不需要检查result[a][b][c],而是需要检查result[a] 是否是字典,如果是,则result[a][b] 是否是字典等等,这样重复且容易出错?

也许最简单的方法是从字典中删除任何值为NSNull 的键,这样下次你请求该值时,你会得到一个普通的nil,它可以安全地根据通常的复合消息传递规则?

NSJSONSerialization 不会为您这样做,但事后添加它很容易:

@interface NSDictionary(RemoveNullValues)
- (NSDictionary *)ty_collectionWithoutNullValues;
@end

@interface NSArray(RemoveNullValues)
- (NSArray *)ty_collectionWithoutNullValues;
@end

[...]

@implementation NSDictionary(RemoveNullValues)

- (NSDictionary *)ty_collectionWithoutNullValues {

    NSMutableDictionary *reducedDictionary = [self mutableCopy];

    // remove any keys for which NSNull is the direct value
    NSArray *keysEvaluatingToNull = [self allKeysForObject:[NSNull null]];
    [reducedDictionary removeObjectsForKeys:keysEvaluatingToNull];

    // ask any child dictionaries to do the same; note that it's safe
    // to mutate reducedDictionary in this array because allKeys is a 
    // copy property; what you're iterating is not reducedDictionary 
    // but a snapshot of its keys when the array first began
    for (id key in [reducedDictionary allKeys]) {
        id child = reducedDictionary[key];
        if ([child respondsToSelector:@selector(ty_collectionWithoutNullValues)]) {
            reducedDictionary[key] = [child ty_collectionWithoutNullValues];
        }
    }

    return [reducedDictionary copy];
}

@end

@implementation NSArray(RemoveNullValues)
- (NSArray *)ty_collectionWithoutNullValues {
    NSMutableArray *reducedArray = [NSMutableArray array];

    for (id child in self) {
        if ([child isKindOfClass:[NSNull class]]) continue;

        if ([child respondsToSelector:@selector(ty_collectionWithoutNullValues)]) {
            [reducedArray addObject:[child ty_collectionWithoutNullValues]];
        } else {
            [reducedArray addObject:child];
        }
   }

   return [reducedArray copy];
}
@end

【讨论】:

  • 这个解决方案似乎是最好的,但现在我无法让它在我的代码中工作。
  • @WolfgangGiesel - 如果数组中有字典,可以任意组合,这在 JSON 中并不少见?如果是这样,您需要遍历整个 JSON 结构以查找字典,然后将此答案应用于您找到的内容。
  • 是的,抱歉,临时写的:假设一个顶级字典只有子字典。它确实需要扩展以处理NSArray 案例。我稍后会尝试编辑;暂时标记为社区 wiki,以防其他人想要介入。
  • 已更新并尝试过滤数组。
【解决方案2】:

使用 if(![returnedDict[@"data"][@"weather"][day][@"tides"] isKindOfClass:[NSNull class]]) { some code }

【讨论】:

  • 这仅在最后一个值为NSNull时有效,如果其他任何一个值为NSNull,则应用程序将崩溃。
【解决方案3】:

必须阅读此答案以及已接受的答案并且对问题Is there NSMutableDictionary literal syntax to remove an element?

从链接的答案开始,您可以悄悄删除所有NSNull 并返回nil,而不是如果您使用文字语法访问元素(即使用objectForKey:)通过将以下内容添加到您的应用程序:

@implementation NSDictionary (ClobberNSNull)

- (id) objectForKeyedSubscript:(id<NSCopying>)key
{
   id result = [self objectForKey:key];
   return result == NSNull.null ? nil : result;
}

@end

现在当你使用语法时:

dictionary[key]

如果匹配对象是NSNull,则返回nil,就好像该键不存在一样。

有一些注意事项,请参阅链接的问题,您需要确定这种方法是否适合您的情况。但这很简单。

HTH

注意:在有人 cmets 之前,NSNull 是一个单例,所以 == 是可以的。

【讨论】:

  • 看来它 (a) 有效 (b) 解决了问题 (c) 遵循 Apple 模式并且 (d) 包含 caveat 并且它赢得了无声的反对票?苛刻。
  • 免责声明:反对票不是来自我。话虽这么说:也许需要注意的是这会影响所有被冒犯的字典?
  • @Tommy - 这是一个警告(虽然可能不是一个重要的警告),也许你是对的,这是冒犯的。谁知道?
猜你喜欢
  • 2015-04-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-07-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多