Object是NSMutableDictionary的子类,但在mutate方法(NSJSONSerialization)上崩溃

时间:2014-07-02 22:47:43

标签: 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电话中得到了这个例外:

  

* 由于未捕获的异常'NSInternalInconsistencyException'而终止应用程序,原因:' - [__ NSCFDictionary setObject:forKey:]:发送到不可变对象的mutating方法'

使用顶级字典对象解析JSON时,NSJSONSerialization返回一个不可变的字典对象,表示它是一个NSMutableDictionary,但在尝试改变时会引发异常。

我知道我可以传递NSJSONReadingMutableContainers选项来获取可变容器。但是引擎盖下发生了什么?为什么一个类说它是一个可变的子类,但后来表现得好像它是不可变的?

编辑以澄清问题:我知道有几种方法可以使这段代码有效。我可以在结果上调用mutableCopy或使用NSJSONReadingMutableContainers选项获取可变结果。这里的要点是一个对象说它的类型是NSMutableDictionary或它的子类,然后当我试图改变它时它会导致崩溃。为什么会出现这种行为?它应该被视为一个错误吗?或者这是Objective-C运行时的一些预期的怪癖吗?

1 个答案:

答案 0 :(得分:4)

因为你试图在result(你的NSCFDictionary - immutable)而不是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类时,结果是正确的结果,因为NSCFDictionary是一个匹配NSDictionary和NSMutableDictionary的类集群。 (见What is an NSCFDictionary?)。

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