Recursivamente atraviesa NSDictionary de estructura desconocida

¿Alguien ha hecho un recorrido orderado recursivo de un oficial de la NS de estructura desconocida? Me gustaría tomar cualquier NSDictionary y procesar cada nivel en order jerárquico.

1) Estos datos provienen de JSON validado. ¿Es seguro decir que el NSDictionary creado a partir de un marco como SBJSON (JSON Framework) solo resultaría en una combinación de dictionarys nesteds, matrices y hojas arbitrarias?

2) ¿Cómo se puede hacer un recorrido genérico usando una enumeración rápida que funciona tanto para matrices como para dictionarys? Con el código siguiente, una vez que llego a un dictionary dentro de una matriz, deja de atravesar. Sin embargo, si continúo la recursión en la condición de la matriz (para comprobar si hay dictionarys dentro de las matrices), se libera en la siguiente iteración del id value = [dict valueForKey:key]; con un -[__NSCFDictionary length]: unrecognized selector sent to instance SIGABRT. No sé por qué esto sería un problema, porque ya superé esa línea con un dictionary de nivel superior (donde se encontraron los dictionarys de subnivel).

 -(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]); } } } } 

Muchas gracias

He hecho algo similar en el que atravesaría un object estructurado JSON proveniente de un service web y convertiría cada elemento en una versión mutable.

 - (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); } } 

Necesitaba saber los nombres key para los valores, así que reescribí lo que Joel tenía y propuso esto:

 - (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 (ie it's not a dictionary or array) so its a key/value that we needed NSLog(@"We found key %@ with value %@", keyName, object); } } 

Y luego lo llamarías así:

 [self enumerateJSONToFindKeys:JSON forKeyNamed:nil]; 

De forma alternativa, si desea hacer que una ruta de key determinada sea mutable (para que pueda volver a escribirla usando setValue:forKeyPath: , puede hacer algo como a continuación:

 - (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]; } } }