2009-09-22 23 views
18

Czy jest jakiś sposób uzyskania dostępu do elementu NSArray za pomocą valueForKeyPath? Usługa odwrotnego geokodera Google zwraca na przykład bardzo złożoną strukturę danych. Jeśli chcę, aby miasto, teraz muszę podzielić go na dwa połączenia, podobnie jak to:Uzyskiwanie elementów tablicy z wartościąForKeyPath

NSDictionary *address = [NSString stringWithString:[[[dictionary objectForKey:@"Placemark"] objectAtIndex:0] objectForKey:@"address"]]; 
NSLog(@"%@", [address valueForKeyPath:@"AddressDetails.Country.AdministrativeArea.SubAdministrativeArea.Locality.LocalityName"]); 

prostu zastanawiasz się, czy jest jakiś sposób na shoehorn ten objectAtIndex: wezwanie do łańcucha valueForKeyPath. Wypróbowałem sformułowanie w formacie javascript, takie jak @ "Oznaczenie miejsca [0] .address", ale bez kości.

Odpowiedz

17

Niestety, nie. Pełna dokumentacja dotycząca dozwolonego używania kodowania wartości kluczowej to here. Nie ma, według mojej wiedzy, żadnych operatorów, które pozwalają ci chwytać konkretną tablicę lub ustawić obiekt.

+0

Możesz pobrać konkretną tablicę. Nie wiem, czy uzyskać element tablicy. Zobacz http://stackoverflow.com/questions/3165290/how-to-parsing-json-object-in-iphone-sdk-xcode-using-json-framework – Fraggle

+2

Proszę zaktualizować link w tej odpowiedzi, strona już nie istnieje . – ZeMoon

+0

Zaktualizowano link. – codehearted

15

Oto kategoria Właśnie napisał do NSObject, które mogą obsługiwać indeksów tablicy, dzięki czemu można uzyskać dostęp do zagnieżdżonego obiektu tak: „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 

Używaj go jak tak

NSString* personsFriendsName = [obj valueForKeyPathsWithIndexes:@"me.friends[0].name"]; 

Nie ma sprawdzania błędów, więc jest podatny na złamanie, ale masz pomysł.

+4

Nie ma znaczenia, skoro mamy ulepszoną dosłowną składnię Obj-C. Możesz napisać oryginalną wypowiedź w moim pytaniu jako 'NSDictionary * address = dictionary [@" Oznaczenie miejsca "] [0] [@" address "];' – jsd

+2

Tak, nowa składnia jest świetna. Używam mojego przykładu powyżej w scenariuszu, w którym zewnętrzna struktura danych może się zmienić, więc selektor string jest bardzo pomocny. – psy

+0

@jsd Wciąż może się przydać, gdy jest używany z wiązaniami kakaowymi lub z operatorami takimi jak '@ sum'. Zwłaszcza w przypadku używania z tymczasowymi etykietami debugowania. –

3

Możesz przechwycić klawiaturę w obiekcie trzymając NSArray.

W twoim przypadku keypath będzie oznaczać Placemark0.address ... Override valueForUndefinedKey; poszukaj indeksu w keypath; coś takiego:

-(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]; 
} 

Działa to bardzo dobrze w przypadku modeli, np. Mantle.

Powiązane problemy