2012-02-08 172 views
13

有没有人做过一个未知结构的NSDictionary的递归遍历?我想采取任何NSDictionary并按层次顺序处理每个级别。递归遍历未知结构的NSDictionary

1)此数据来自验证的JSON。可以肯定地说,从像SBJSON(JSON Framework)这样的框架创建的NSDictionary只会导致嵌套字典,数组和任意叶子的组合?

2)如何使用适用于数组和字典的快速枚举来完成泛型遍历?用下面的代码,一旦我得到一个数组中的字典,它会停止遍历。但是,如果我在数组条件中继续递归(以检查数组中的字典),它会在id value = [dict valueForKey:key];的下一次迭代中使用-[__NSCFDictionary length]: unrecognized selector sent to instance SIGABRT。我不知道为什么这会是一个问题,因为我已经通过了顶级字典(其中发现了子级字典数组)的那一行。

-(void)processParsedObject:(id)dict counter:(int)i parent:(NSString *)parent 
{ 
    for (id key in dict) { 
     id value = [dict valueForKey:key]; 
     NSLog(@"%i : %@ : %@ -> %@", i, [value class], parent, key); 

     if ([value isKindOfClass:[NSDictionary class]]) 
     { 
      i++; 
      NSDictionary* newDict = (NSDictionary*)value; 
      [self processParsedObject:newDict counter:i parent:(NSString*)key]; 
      i--; 
     } 
     else if ([value isKindOfClass:[NSArray class]]) 
     { 
      for (id obj in value) { 
       NSLog(@"Obj Type: %@", [obj class]); 
      } 
     } 
    } 
} 

非常感谢

+0

你每当你NSLog一个NSDictionary都这样做。 – 2012-02-08 04:09:45

+0

没错,但总的来说就是捕获和处理过程中的嵌套对象,而不仅仅是记录它们。 – 2012-02-08 17:33:20

+0

你只需要学习如何使用'isKindOfClass'。 – 2012-02-08 18:30:12

回答

31

我已经做了类似的东西在那里我会遍历JSON结构化对象从Web服务来了,每个元素转换为可变的版本。

- (void)processParsedObject:(id)object 
{ 
    [self processParsedObject:object depth:0 parent:nil]; 
} 

- (void)processParsedObject:(id)object depth:(int)depth parent:(id)parent 
{  
    if ([object isKindOfClass:[NSDictionary class]]) 
    { 
     for (NSString* key in [object allKeys]) 
     { 
      id child = [object objectForKey:key]; 
      [self processParsedObject:child depth:(depth + 1) parent:object]; 
     } 
    } 
    else if ([object isKindOfClass:[NSArray class]]) 
    { 
     for (id child in object) 
     { 
      [self processParsedObject:child depth:(depth + 1) parent:object]; 
     } 
    } 
    else 
    { 
     // This object is not a container you might be interested in it's value 
     NSLog(@"Node: %@ depth: %d", [object description], depth); 
    } 
} 
+0

非常好。我会给这个镜头并报告回来。 – 2012-02-08 03:20:50

+0

工程就像一个魅力!我喜欢你如何将它分解为一个参数方法,因此调用者不需要知道模糊的参数。 – 2012-02-08 03:26:11

+0

你为什么通过“父母”?看起来它并没有被使用过。 – 2012-08-24 19:44:31

4

我需要知道的键名的值,所以我改写了乔尔有什么以及与此想出了:

- (void)enumerateJSONToFindKeys:(id)object forKeyNamed:(NSString *)keyName 
{ 
    if ([object isKindOfClass:[NSDictionary class]]) 
    { 
     // If it's a dictionary, enumerate it and pass in each key value to check 
     [object enumerateKeysAndObjectsUsingBlock:^(id key, id value, BOOL *stop) { 
      [self enumerateJSONToFindKeys:value forKeyNamed:key]; 
     }]; 
    } 
    else if ([object isKindOfClass:[NSArray class]]) 
    { 
     // If it's an array, pass in the objects of the array to check 
     [object enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { 
      [self enumerateJSONToFindKeys:obj forKeyNamed:nil]; 
     }]; 
    } 
    else 
    { 
     // If we got here (i.e. it's not a dictionary or array) so its a key/value that we needed 
     NSLog(@"We found key %@ with value %@", keyName, object); 
    } 
} 

然后你把它想:

[self enumerateJSONToFindKeys:JSON forKeyNamed:nil]; 

另外,如果你想让一个给定的键路径可变(所以你可以使用setValue:forKeyPath:写回它),你可以做一些像下面这样的东西:

- (void)makeDictionariesMutableForKeyPath:(NSString *)keyPath { 
    NSArray *keys = [keyPath componentsSeparatedByString:@"."]; 

    NSString *currentKeyPath = nil; 
    for (NSString *key in keys) { 
     if (currentKeyPath) { 
      NSString *nextKeyPathAddition = [NSString stringWithFormat:@".%@", key]; 
      currentKeyPath = [currentKeyPath stringByAppendingString:nextKeyPathAddition]; 
     } else { 
      currentKeyPath = key; 
     } 

     id value = [self.mutableDictionary valueForKeyPath:currentKeyPath]; 
     if ([value isKindOfClass:NSDictionary.class]) { 
      NSMutableDictionary *mutableCopy = [(NSDictionary *)value mutableCopy]; 
      [self.mutableDictionary setValue:mutableCopy forKeyPath:currentKeyPath]; 
     } 
    } 

} 
+0

嗨,有没有办法返回所有ketPath? ...像所有子键“keyname.keyname.keyname”? – Mike97 2015-06-02 16:44:47

+0

... oops ... keypath – Mike97 2015-06-02 16:54:10