There's an NSObject category that extends valueForKeyPath
to give valueForKeyPathWithIndexes
. It lets you write this:
NSDictionary *dict = @{@"result": @[@{@"name": @"John"}, @{@"name": @"Mary"}]};
NSString *path = @"result[0].name";
NSString *answer = [dict valueForKeyPathWithIndexes:path];
XCTAssertEqualStrings(answer, @"John");
The category is by psy, here: Getting array elements with valueForKeyPath
@interface NSObject (ValueForKeyPathWithIndexes)
-(id)valueForKeyPathWithIndexes:(NSString*)fullPath;
@end
#import "NSObject+ValueForKeyPathWithIndexes.h"
@implementation NSObject (ValueForKeyPathWithIndexes)
-(id)valueForKeyPathWithIndexes:(NSString*)fullPath
{
NSRange testrange = [fullPath rangeOfString:@"["];
if (testrange.location == NSNotFound)
return [self valueForKeyPath:fullPath];
NSArray* parts = [fullPath componentsSeparatedByString:@"."];
id currentObj = self;
for (NSString* part in parts)
{
NSRange range1 = [part rangeOfString:@"["];
if (range1.location == NSNotFound)
{
currentObj = [currentObj valueForKey:part];
}
else
{
NSString* arrayKey = [part substringToIndex:range1.location];
int index = [[[part substringToIndex:part.length-1] substringFromIndex:range1.location+1] intValue];
currentObj = [[currentObj valueForKey:arrayKey] objectAtIndex:index];
}
}
return currentObj;
}
@end
Plain old valueForKeyPath
will get you close, but not exactly what you asked for. It may be useful in this form though:
NSDictionary *dict = @{@"result": @[@{@"name": @"John"}, @{@"name": @"Mary"}]};
NSString *path = @"result.name";
NSString *answer = [dict valueForKeyPath:path];
XCTAssertEqualObjects(answer, (@[@"John", @"Mary"]));