运行此代码:
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运行时的一些预期的怪癖吗?
答案 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的子类(或成员类)。