NSJSONSerialization不创build可变容器

代码如下:

NSError *parseError; NSMutableArray *listOfObjects = [NSJSONSerialization JSONObjectWithData:[@"[]" dataUsingEncoding:NSUTF8StringEncoding] options:NSJSONReadingMutableContainers error:&parseError]; NSLog(@"Is mutable? %li", [listOfObjects isKindOfClass:[NSMutableArray class]]); listOfObjects = [NSJSONSerialization JSONObjectWithData:[@"[[],{}]" dataUsingEncoding:NSUTF8StringEncoding] options:NSJSONReadingMutableContainers error:&parseError]; NSLog(@"Is mutable? %li", [listOfObjects isKindOfClass:[NSMutableArray class]]); 

正如你所看到的,我调用完全相同的方法来parsingJSON,JSON中有一个空的列表,然后是一个里面有一个对象的列表。 结果如下:

 Is mutable? 0 Is mutable? 1 

问题是,NSJSONSerialization似乎没有遵循选项来创build空列表的可变容器。 对我来说似乎是一个错误,但也许我只是误解了一些东西。

有任何想法吗?

这和预期的一样:

 NSString *s = @"{ \"objs\": [ \"a\", \"b\" ] }"; NSData *d = [NSData dataWithBytes:[s UTF8String] length:[s length]]; id dict = [NSJSONSerialization JSONObjectWithData:d options:NSJSONReadingMutableContainers error:NULL]; NSLog(@"%@", dict); [[dict objectForKey:@"objs"] addObject:@"c"]; NSLog(@"%@", dict); NSLog(@"%@", [[dict objectForKey:@"objs"] class]); 

这是控制台输出:

 2012-03-28 13:49:46.224 ExampleRunner[42526:707] { objs = ( a, b ); } 2012-03-28 13:49:46.225 ExampleRunner[42526:707] { objs = ( a, b, c ); } 2012-03-28 13:49:46.225 ExampleRunner[42526:707] __NSArrayM 

编辑

请注意,如果我们将以下行添加到上面的代码中…

 NSLog(@"%@", [[dict objectForKey:@"objs"] superclass]); 

…我们在控制台上得到以下输出:

 2012-03-28 18:09:53.770 ExampleRunner[42830:707] NSMutableArray 

…以防万一不清楚__NSArrayMNSMutableArray的私有子类,从而certificateOP的代码确实按预期工作(除了他的NSLog语句)。

编辑

哦,顺便说一下,下面的代码行…

 NSLog(@"%d", [[dict objectForKey:@"objs"] isKindOfClass:[NSMutableArray class]]); 

…导致以下控制台输出:

 2012-03-28 18:19:19.721 ExampleRunner[42886:707] 1 

编辑(回应改变的问题)

有趣…看起来像一个错误。 给出以下代码:

 NSData *dictData2 = [@"{ \"foo\": \"bar\" }" dataUsingEncoding:NSUTF8StringEncoding]; id dict2 = [NSJSONSerialization JSONObjectWithData:dictData2 options:NSJSONReadingMutableContainers error:NULL]; NSLog(@"%@", [dict2 class]); NSLog(@"%@", [dict2 superclass]); NSLog(@"%d", [dict2 isKindOfClass:[NSMutableDictionary class]]); // This works... [dict2 setObject:@"quux" forKey:@"baz"]; NSLog(@"%@", dict2); NSData *dictData = [@"{}" dataUsingEncoding:NSUTF8StringEncoding]; id emptyDict = [NSJSONSerialization JSONObjectWithData:dictData options:NSJSONReadingMutableContainers error:NULL]; NSLog(@"%@", [emptyDict class]); NSLog(@"%@", [emptyDict superclass]); NSLog(@"%d", [emptyDict isKindOfClass:[NSMutableDictionary class]]); //...but this fails: [emptyDict setObject:@"quux" forKey:@"baz"]; NSLog(@"%@", emptyDict); 

这是控制台输出:

 2012-03-29 09:40:52.781 ExampleRunner[43816:707] NSMutableDictionary 2012-03-29 09:40:52.782 ExampleRunner[43816:707] 1 2012-03-29 09:40:52.782 ExampleRunner[43816:707] __NSCFDictionary 2012-03-29 09:40:52.782 ExampleRunner[43816:707] NSMutableDictionary 2012-03-29 09:40:52.783 ExampleRunner[43816:707] 1 2012-03-29 09:40:52.783 ExampleRunner[43816:707] { baz = quux; foo = bar; } 2012-03-29 09:40:52.784 ExampleRunner[43816:707] __NSCFDictionary 2012-03-29 09:40:52.784 ExampleRunner[43816:707] NSMutableDictionary 2012-03-29 09:40:52.784 ExampleRunner[43816:707] 1 2012-03-29 09:40:52.785 ExampleRunner[43816:707] NSException: -[__NSCFDictionary setObject:forKey:]: mutating method sent to immutable object 

所以这样创build的空数组和字典似乎没有预期的那样。

这是我对这个问题的解决方法:

 #import "NSJSONSerialization+MutableBugFix.h" @implementation NSJSONSerialization (NSJSONSerialization_MutableBugFix) + (id)JSONObjectWithDataFixed:(NSData *)data options:(NSJSONReadingOptions)opt error:(NSError **)error { id object = [NSJSONSerialization JSONObjectWithData:data options:opt error:error]; if (opt & NSJSONReadingMutableContainers) { return [self JSONMutableFixObject:object]; } return object; } + (id)JSONMutableFixObject:(id)object { if ([object isKindOfClass:[NSDictionary class]]) { // NSJSONSerialization creates an immutable container if it's empty (boo!!) if ([object count] == 0) { object = [object mutableCopy]; } for (NSString *key in [object allKeys]) { [object setObject:[self JSONMutableFixObject:[object objectForKey:key]] forKey:key]; } } else if ([object isKindOfClass:[NSArray class]]) { // NSJSONSerialization creates an immutable container if it's empty (boo!!) if (![object count] == 0) { object = [object mutableCopy]; } for (NSUInteger i = 0; i < [object count]; ++i) { [object replaceObjectAtIndex:i withObject:[self JSONMutableFixObject:[object objectAtIndex:i]]]; } } return object; } @end 

所以我打电话给:

 NSDictionary *object = [NSJSONSerialization JSONObjectWithDataFixed:jsonData options:NSJSONReadingMutableContainers error:&err]; 

而不是通常的:

 NSDictionary *object = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingMutableContainers error:&err]; 

其他人也把这个错误,看看

  1. https://github.com/couchbaselabs/TouchDB-iOS/issues/44&#x6216;
  2. 例如, https://github.com/johnlabarge/jlbiosutils/blob/master/jlbiosutils/DynamicProperties.m

在后一种情况下,您可以看到空字典的完整解决方法(请参阅DynamicGetter(...)方法)。

这是我做的:

 BOOL needsWorkaround = YES; if (needsWorkaround) { NSMutableDictionary* appState2 = (__bridge_transfer NSMutableDictionary*) CFPropertyListCreateDeepCopy ( kCFAllocatorDefault, (__bridge void*)appState, kCFPropertyListMutableContainersAndLeaves ); appState = appState2; }