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.
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.
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.
//
// 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);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With