Search code examples
iphoneiosxcodensarraynsdictionary

Searching for an object in an unknown NSDictionary/NSArray depth


I've already asked a similar question but this is slightly different so i Thought it would be fine to ask another question.

I'm storing Arrays within Arrays, as well as NSDictionaries. It's a utility kind of application and there is no set structure, the user can enter nested information as much as they require.

I need a method that can scroll through the entire contents of an Array/Dictionary and return the specific dictionary based on a value that I send the method. Here's an example..

NSMutableArray *array = [[NSMutableArray alloc]init];

NSMutableDictionary *enteredItem = [[NSMutableDictionary alloc]init];

[enteredItem setObject:@"i'm a title"       forKey:@"title"];
[enteredItem setObject:@"i'm an id"         forKey:@"id"];
[enteredItem setObject:@"i'm a description" forKey:@"description"];
[enteredItem setObject:@"i'm a timestamp"   forKey:@"timestamp"];
[enteredItem setObject:array                forKey:@"items"];

[array addObject:enteredItem];
[array addObject:anotherDictionary];
[array addObject:moreDictionaries];

So in the example above, I would need to find (return) the dictionary that contains "i'm an id".

The similar question I asked is located here.. Searching for a value in an unknown NSMutableArray depth - I'm having trouble returning a dictionary and also comparing the object.

Hopefully my question is clear. Thanks for any help you can offer.


Solution

  • Continuing from the answer, you need to do some modification:

    - (id)findDictionaryWithValue:(id)value inArray:(NSArray *)array
    {
        __block id match = nil;
        [array enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
            if ([obj isKindOfClass:[NSArray class])
            {
                match = [self findDictionaryWithValue:value inArray:obj];
            }
            else if ([obj isKindOfClass:[NSDictionary class])
            {
                match = [self findDictionaryWithValue:value inDictionary:obj];
            }
            *stop = (match!=nil);
        }];
        return match;
    }
    
    - (id)findDictionaryWithValue:(id)value inDictionary:(NSDictionary *)dict;
    {
        __block id match = nil;
        [dict enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
            if([obj isEqual:value]) {
                match = dict;
            } 
             else if ([obj isKindOfClass:[NSArray class])
            {
                match = [self findDictionaryWithValue:value inArray:obj];
    
            }
            else if ([obj isKindOfClass:[NSDictionary class])
            {
                match = [self findDictionaryWithValue:value inDictionary:obj];
            }
            *stop = (match!=nil);
        }];
        return match;
    }
    
    NSDictionary *resultDict = [self findDictionaryForValue:@"i'm an id" inArray:array];
    

    However, you must be careful with recursion. If there is any circular path, you will get an infinite loop( and stack overflow before crash).