2011-08-22 102 views
2

我已经与这部分代码的方法:的NSDictionary for循环异常

NSDictionary *tmpDict = [self getJsonDictionary]; 

NSInteger tmpID; 

for (NSDictionary *d in tmpDict) { 
    tmpID = [[d objectForKey:@"id"] integerValue]; 
} 

tmpDict是具有可变大小的NSDictionary。如果tmpDict含有至少2个对象(2 NSDictionary中)它工作得很好,但如果只包含1个对象(1 NSDictionary中)抛出此异常:

-[NSCFString objectForKey:]: unrecognized selector sent to instance 0x4e866d0 
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NSCFString objectForKey:]: unrecognized selector sent to instance 0x4e866d0' 

为什么呢?如何修复如果tmpDict只有1个对象?

可能for (NSDictionary *d in tmpDict)是问题,当tmpDict有1个对象dNSCFString,但是为什么?

- UPDATE

问题是,当tmpDict有1个项目(一个的NSDictionary)的for (NSDictionary *d in tmpDict)采取各种键/值项的字典,这是异常的原因。否则,如果tmpDict有2+项是NSDictionary的NSDictionary,它运作良好。我需要一种方法来解决这个问题,仍然使用for循环。想法?

- 更新2 *

其实这段代码的作品,但它是多余的:

if ([tmpObject isKindOfClass:[NSDictionary class]]) { 
    tmpID = [[tmpObject objectForKey:@"id"] integerValue]; 
    tmpProp2 = [tmpObject objectForKey:@"prop2"]; 
    tmpProp3 = [tmpObject objectForKey:@"prop3"]; 
    tmpProp4 = [tmpObject objectForKey:@"prop4"]; 
} else if ([tmpObject isKindOfClass:[NSArray class]]) { 
    for (NSDictionary *d in tmpObject) { 
     tmpID = [[d objectForKey:@"id"] integerValue]; 
     tmpProp2 = [d objectForKey:@"prop2"]; 
     tmpProp3 = [d objectForKey:@"prop3"]; 
     tmpProp4 = [d objectForKey:@"prop4"]; 
    } 
} 

它需要改进。

+0

WRT更新2:唯一的改进是你可以从字典中获取项目。否则,这看起来不错。 –

回答

3

我很惊讶,它在所有工作实际。对于字典,快速列举枚举。这就是为什么它告诉你-objectForKey:已发送到NSCFString,因为来自JSON的字典的密钥始终是一个字符串。

你应该,也许,这样做:

for (id d in [tmpDict objectEnumerator]) 
{ 
    // Objects in a JSON dictionary aren't necessarily dictionaries 
    if([d isKindOfClass:[NSDictionary class]]) 
    { 
     tmpID = [[d objectForKey:@"id"] integerValue]; 
    } 
} 

一个可能的原因可能有两个库的工作是,如果顶级项目实际上是一个数组,而不是一本字典。如果您有:

[ { "id" : 1 }, { "id" : 2 } ] 

您的JSON解析器会给你一个NSArray,而不是一个NSDictionary,它可以与你的代码,即使你认为你的顶级项目是一个字典解析。

编辑:看到您的更新,我相信这是发生了什么。如果你有一个对象,你的JSON字符串看起来像:

{ "id" : 1, "prop2" : "value1", "prop3" : "value1", "prop4" : "value1" } 

如果你有两个对象,它可能是这样的:

[ 
     { "id" : 1, "prop2" : "value1", "prop3" : "value1", "prop4" : "value1" }, 
     { "id" : 2, "prop2" : "value1", "prop3" : "value1", "prop4" : "value1" } 
] 

声明的方括号,这意味着JSON阵列。

+0

谢谢你的回复,你能解释一下为什么你使用'objectEnumerator'?检查我的新更新 –

+0

@Fred:因为objectEnumerator返回的是对象而不是键 – JeremyP

+0

@Fred:你的最新更新与我在我的答案的第二部分中的推测是一致的。如果你有一本字典,那么你的JSON就是一本字典,如果你有超过o ne字典你的JSON是字典的一个数组。 – JeremyP

2

由于在tmpDict变量中存在NSString类型的对象,因此可以使用此错误。

for (id *d in tmpDict) 
{ 
    if([d isKindOfClass:[NSDictionary class]]) 
     tmpID = [[d objectForKey:@"id"] integerValue]; 
    else 
     tmpID = [(NSString *)d intValue]; 
} 

,而不是这个

for (NSDictionary *d in tmpDict) { 
    tmpID = [[d objectForKey:@"id"] integerValue]; 
} 
+0

没关系,但我需要'tmpID = [[tmpDict objectForKey @“id”] integerValue]'如果d不是NSDictionary(如果tmpDict只有1个项目,我仍然需要取对象,但我应该使用'[tmpDict objectForkey ]' –

+0

这可以工作,但如果在NSDictionary中有多个键/值对,则else块重复。 –

+0

您可以在for循环的末尾检查是否更新tmpID值,如果是的,那么不要改变它的值 – Robin