Recursively traverse NSDictionary of unknown structure Recursively traverse NSDictionary of unknown structure json json

Recursively traverse NSDictionary of unknown structure


I've done something similar where I would traverse a JSON structured object coming from a web service and convert each element into a mutable version.

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


I needed to know the key names for the values so I rewrote what Joel had and came up with this:

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

And then you'd call it like:

[self enumerateJSONToFindKeys:JSON forKeyNamed:nil];

Alternatively, if you wanted to make a given key path mutable (so you could write back to it using setValue:forKeyPath:), you could do something like below:

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