Is there any way to access an NSArray
element with valueForKeyPath
? Google's reverse geocoder service, for example, returns a very complex data structure. If I want to get the city, right now I have to break it into two calls, like this:
NSDictionary *address = [NSString stringWithString:[[[dictionary objectForKey:@"Placemark"] objectAtIndex:0] objectForKey:@"address"]];
NSLog(@"%@", [address valueForKeyPath:@"AddressDetails.Country.AdministrativeArea.SubAdministrativeArea.Locality.LocalityName"]);
Just wondering if there's a way to shoehorn the objectAtIndex:
call into the valueForKeyPath
string. I tried a javascript-esque formulation like @"Placemark[0].address" but no dice.
Unfortunately, no. The full documentation for what's allowed using Key-Value Coding is here. There are not, to my knowledge, any operators that allow you to grab a particular array or set object.
Here's a category I just wrote for NSObject that can handle array indexes so you can access a nested object like this: "person.friends[0].name"
@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
Use it like so
NSString* personsFriendsName = [obj valueForKeyPathsWithIndexes:@"me.friends[0].name"];
There's no error checking, so it's prone to breaking but you get the idea.
You can intercept the keypath in the object holding the NSArray.
In your case the keypath would become Placemark0.address... Override valueForUndefinedKey; look for the index in the keypath; something like this:
-(id)valueForUndefinedKey:(NSString *)key
{
// Handle paths like Placemark0, Placemark1, ...
if ([key hasPrefix:@"Placemark"])
{
// Caller wants to access the Placemark array.
// Find the array index they're after.
NSString *indexString = [key stringByReplacingOccurrencesOfString:@"Placemark" withString:@""];
NSInteger index = [indexString integerValue];
// Return array element.
if (index < self.placemarks.count)
return self.placemarks[index];
}
return [super valueForUndefinedKey:key];
}
This works really well for model frameworks e.g. Mantle.
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