ios - 对象是 NSMutableDictionary 的子类,但在 mutate 方法 (NSJSONSerialization) 上崩溃

标签 ios objective-c nsdictionary nsmutabledictionary nsjsonserialization

运行这段代码:

NSData *jsonData = [@"{\"foo\":\"bar\"}" dataUsingEncoding:NSUTF8StringEncoding];
id result = [NSJSONSerialization JSONObjectWithData:jsonData options:0 error:nil];
if ([result isKindOfClass:[NSMutableDictionary class]])
{
    NSMutableDictionary *dict = (NSMutableDictionary *)result;
    [dict setObject:@"foo" forKey:@"baz"];
}

并且您从 setObject 调用中得到了这个异常:

* Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: '-[__NSCFDictionary setObject:forKey:]: mutating method sent to immutable object'

当使用顶级字典对象解析 JSON 时,NSJSONSerialization 返回一个不可变的字典对象,表明它是一个 NSMutableDictionary 但当您尝试改变它时抛出异常.

我知道我可以通过 NSJSONReadingMutableContainers 选项来获取可变容器。但幕后发生了什么?为什么一个类说它是一个可变的子类,但随后却表现得好像它是不可变的?

编辑以澄清问题:我知道有几种方法可以使此代码正常工作。我可以对结果调用 mutableCopy 或使用 NSJSONReadingMutableContainers 选项来获得可变结果。这里的重点是一个对象说它的类型是 NSMutableDictionary 或其子类,然后当我尝试改变它时它会导致崩溃。为什么会存在这种行为?它应该被认为是一个错误吗?或者这是 Objective-C 运行时的一些预期怪癖?

最佳答案

因为您试图在 result(您的 NSCFDictionary -- 不可变)而不是 dict(您的转换 NSMutableDictionary)上为键设置对象。

相反,尝试:

NSData *jsonData = [@"{\"foo\":\"bar\"}" dataUsingEncoding:NSUTF8StringEncoding];
id result = [NSJSONSerialization JSONObjectWithData:jsonData options:0 error:nil];
if ([result isKindOfClass:[NSDictionary class]])
{
    NSMutableDictionary *dict = [result mutableCopy];
    [dict setObject:@"foo" forKey:@"baz"];
}

当您尝试确定结果是否适合 NSMutableDictionary 类时,结果传递为 true 的原因是因为 NSCFDictionary 是一个匹配 NSDictionary 和 NSMutableDictionary 的类簇。 (参见 What is an NSCFDictionary?)。

本质上(在那个 if 语句中),您实际上根本没有检查 NSCFDictionary 是否可变——您只是检查它是否是 NSMutableDictionary 的子类(或成员类)。

关于ios - 对象是 NSMutableDictionary 的子类,但在 mutate 方法 (NSJSONSerialization) 上崩溃,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24542286/

相关文章:

ios - 我可以重置 CFBundleShortVersionString

ios - 具有多个对象和键的 NSDictionary init

objective-c - 使用具有多个值的键创建 NSDictionary

ios - 特定对象后的 NSDictionary 为空?

iphone - 如何对具有嵌套数组/字典的 NSArray 和 NSDictionary 进行真正的深度复制?

ios - 检查键是否存在于复杂的多维字典中

iphone - MKPinAnnotationView 上的双选触摸

ios - 在 IB 中编辑 Tableview 并失去连接

objective-c - 像 Objective-C 中的 Python 那样的原始字符串

objective-c - 如何在 iPhone 后台运行我的应用程序?