1

In calling NSDictionary valueForKeyPath if one level of the path is an array can you specify a specific element in the array?

For example:

[myDict valueForKeypath:@"customer.contactInfo.phoneNumbers[4].countryCode];

where .phoneNumbers is an NSArray. Or do I have to:

NSArray *numbers=[myDict valueForKeypath:@"customer.contactInfo.phoneNumbers];
NSString *countryCode=[[numbers objectAtIndex:4] objectForKey:@"countryCode"];

It would be really nice and much cleaner if this could be done in one statement.

ChrisP
  • 9,796
  • 21
  • 77
  • 121
  • Looks like the answer is "No": [Getting array elements with valueForKeyPath](http://stackoverflow.com/questions/1461126/getting-array-elements-with-valueforkeypath) – jscs Feb 16 '12 at 19:53

2 Answers2

1

You could do this:

NSString *myString = [[[myDict valueForKeypath:@"customer.contactInfo.phoneNumbers"] objectAtIndex:4] objectForKey:@"countryCode"];
Jorsh
  • 232
  • 1
  • 11
0

Here's a category I wrote for NSObject that can handle array indexes so you can access your nested object like this: "customer.contactInfo.phoneNumbers[4].countryCode"

@interface NSObject (ValueForKeyPathWithIndexes)
   -(id)valueForKeyPathWithIndexes:(NSString*)fullPath;
@end


#import "NSObject+ValueForKeyPathWithIndexes.h"    
@implementation NSObject (ValueForKeyPathWithIndexes)

-(id)valueForKeyPathWithIndexes:(NSString*)fullPath
{
    //quickly use standard valueForKeyPath if no arrays are found
    if ([fullPath rangeOfString:@"["].location == NSNotFound)
        return [self valueForKeyPath:fullPath];

    NSArray* parts = [fullPath componentsSeparatedByString:@"."];
    id currentObj = self;
    for (NSString* part in parts)
    {
        NSRange range = [part rangeOfString:@"["];
        if (range.location == NSNotFound)           
        {
            currentObj = [currentObj valueForKey:part];
        }
        else
        {
            NSString* arrayKey = [part substringToIndex:range.location];
            int index = [[[part substringToIndex:part.length-1] substringFromIndex:range1.location+1] intValue];
            currentObj = [[currentObj valueForKey:arrayKey] objectAtIndex:index];
        }
    }
    return currentObj;
}
@end

Use it like so

NSString* countryCode = [myDict valueForKeyPathWithIndexes:@"customer.contactInfo.phoneNumbers[4].countryCode"];

There's no error checking, so it's prone to breaking but you get the idea. I cross posted this answer to a similar (linked) question.

JakubKnejzlik
  • 6,363
  • 3
  • 40
  • 41
psy
  • 2,791
  • 26
  • 26