Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Reaching to deepest child level in NSDictionary

I have a NSDictionary object with deep structures in it like arrays containing further array which contain dictionaries...

I want to fetch an object down in the hierarchy. Is there any direct indexing way to fetch them using key names or something else?

Its a pain to keep on calling objectForKey methos multiple time to reach to deepest child level.

like image 752
Abhinav Avatar asked May 14 '11 17:05

Abhinav


3 Answers

If you're only using dictionaries, and if the keys in your dictionaries are always strings, you can use key-value coding to traverse several levels of dictionaries:

id someObject = [mainDictionary valueForKey:@"apple.pear.orange.bear"];

This is equivalent to:

NSDictionary *level2Dict = [mainDictionary objectForKey:@"apple"];
NSDictionary *level3Dict = [level2Dict objectForKey:@"pear"];
NSDictionary *level4Dict = [level3Dict objectForKey:@"orange"];
id someObject = [level4Dict objectForKey:@"bear"];

This isn't so convenient, though, if you also have arrays in the mix. See this recent SO discussion for more on this topic.

like image 104
Caleb Avatar answered Nov 05 '22 20:11

Caleb


For a structure that includes Arrays, there is no built in way to do something like:

[dict objectForKey:@"[level1][level2][level3]"]

That being said, anything built in is just code that someone at Apple has written, and you can do the same.

Write a helper class that will do it for you based on a key concatenation scheme that you create, then just call it. It will save the code duplication.

like image 38
coneybeare Avatar answered Nov 05 '22 21:11

coneybeare


//
//  NSDictionary+Path.h
//
//  Created by Wu Li-chih on 10/3/12.
//  Copyright (c) 2012 Wu Li-chih. All rights reserved.
//

#import <Foundation/Foundation.h>

@interface NSDictionary (Path)
- (id) objectForPath:(NSArray*)aKeyPath;
@end

//
//  NSDictionary+Path.m
//
//  Created by Wu Li-chih on 10/3/12.
//  Copyright (c) 2012 Wu Li-chih. All rights reserved.
//

#import "NSDictionary+Path.h"

@implementation NSDictionary (Path)

- (id) objectForPath:(NSArray*)aKeyPath
{
    if([d isKindOfClass:[NSDictionary class]])
        d = [d objectForKey:aKey];
    else if([d isKindOfClass:[NSArray class]])
        d = [d objectAtIndex:[aKey integerValue]];
    else
        return nil;
    if(d == nil)
        return nil;
}


@end

// example
id v = [dict objectForPath:@[@"root", @"sub", @"target_node"]];

NSDictionary *a = @{ @"aaa" : @{ @"bbb": @[@123, @456, @{@"ccc": @"result"}]}};
id r = [a objectForPath:@[@"aaa", @"bbb", @2, @"ccc"]];
STAssertTrue([r isEqualToString:@"result"], nil);
r = [a objectForPath:@[@"aaa", @"bbb", @0, @"ccc"]];
STAssertNil(r, nil);
like image 3
Li-chih Wu Avatar answered Nov 05 '22 20:11

Li-chih Wu