Abhinav
Abhinav

Reputation: 38162

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.

Upvotes: 8

Views: 3594

Answers (3)

Li-chih Wu
Li-chih Wu

Reputation: 1092

//
//  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);

Upvotes: 3

coneybeare
coneybeare

Reputation: 33101

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.

Upvotes: 4

Caleb
Caleb

Reputation: 125007

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.

Upvotes: 8

Related Questions