2012-02-08 14 views
13

Czy ktoś wykonał rekursywne uporządkowane przemieszczenie NSDictionary o nieznanej strukturze? Chciałbym wziąć dowolny NSDictionary i przetworzyć każdy poziom w hierarchicznej kolejności.Rekurencyjnie przechodzić przez NSDictionary o nieznanej strukturze

1) Dane pochodzą ze sprawdzonego JSON. Czy można bezpiecznie powiedzieć, że NSDictionary stworzony z frameworka SBJSON (JSON Framework) spowodowałby tylko połączenie zagnieżdżonych słowników, tablic i dowolnych listków?

2) W jaki sposób można wykonać ogólne przejście przy użyciu szybkiego wyliczania, które działa zarówno w przypadku tablic, jak i słowników? Za pomocą poniższego kodu, gdy dojdę do słownika w tablicy, przestaje on przechodzić. Jeśli jednak kontynuuję rekursję w warstwie tablicowej (w celu sprawdzenia słowników w tablicach), zostanie ona odtworzona w następnej iteracji id value = [dict valueForKey:key]; za pomocą SIGABRT -[__NSCFDictionary length]: unrecognized selector sent to instance. Nie wiem, dlaczego to byłby problem, ponieważ przeszedłem już do tej linii ze słownikiem najwyższego poziomu (gdzie znaleziono tablicę słowników poziomu podrzędnego).

-(void)processParsedObject:(id)dict counter:(int)i parent:(NSString *)parent 
{ 
    for (id key in dict) { 
     id value = [dict valueForKey:key]; 
     NSLog(@"%i : %@ : %@ -> %@", i, [value class], parent, key); 

     if ([value isKindOfClass:[NSDictionary class]]) 
     { 
      i++; 
      NSDictionary* newDict = (NSDictionary*)value; 
      [self processParsedObject:newDict counter:i parent:(NSString*)key]; 
      i--; 
     } 
     else if ([value isKindOfClass:[NSArray class]]) 
     { 
      for (id obj in value) { 
       NSLog(@"Obj Type: %@", [obj class]); 
      } 
     } 
    } 
} 

Dziękujemy

+0

Robisz to za każdym razem, gdy NSLog NSDictionary. –

+0

Dobrze, ale ogólnie rzecz biorąc, celem jest przechwytywanie i przetwarzanie zagnieżdżonych obiektów w procesie, a nie tylko ich rejestrowanie. –

+0

Musisz tylko nauczyć się używać 'isKindOfClass'. –

Odpowiedz

31

robiłem coś podobnego, gdzie chciałbym Przemierzaj JSON zorganizowany obiekt pochodzący z usługą internetową i przekształcić każdy element na zmienny wersji.

- (void)processParsedObject:(id)object 
{ 
    [self processParsedObject:object depth:0 parent:nil]; 
} 

- (void)processParsedObject:(id)object depth:(int)depth parent:(id)parent 
{  
    if ([object isKindOfClass:[NSDictionary class]]) 
    { 
     for (NSString* key in [object allKeys]) 
     { 
      id child = [object objectForKey:key]; 
      [self processParsedObject:child depth:(depth + 1) parent:object]; 
     } 
    } 
    else if ([object isKindOfClass:[NSArray class]]) 
    { 
     for (id child in object) 
     { 
      [self processParsedObject:child depth:(depth + 1) parent:object]; 
     } 
    } 
    else 
    { 
     // This object is not a container you might be interested in it's value 
     NSLog(@"Node: %@ depth: %d", [object description], depth); 
    } 
} 
+0

Doskonały. Dam ci ten strzał i zgłoś się. –

+0

Działa jak urok! Podoba mi się sposób, w jaki został obliczony na metodę jednego param, więc rozmówca nie musi znać niejasnych parametrów. –

+0

Dlaczego przekazujesz 'rodzic'? Wygląda na to, że nigdy nie jest używany. –

4

Musiałem znać nazwy klawiszy dla wartości więc przepisał co miał Joel i podszedł z tym:

- (void)enumerateJSONToFindKeys:(id)object forKeyNamed:(NSString *)keyName 
{ 
    if ([object isKindOfClass:[NSDictionary class]]) 
    { 
     // If it's a dictionary, enumerate it and pass in each key value to check 
     [object enumerateKeysAndObjectsUsingBlock:^(id key, id value, BOOL *stop) { 
      [self enumerateJSONToFindKeys:value forKeyNamed:key]; 
     }]; 
    } 
    else if ([object isKindOfClass:[NSArray class]]) 
    { 
     // If it's an array, pass in the objects of the array to check 
     [object enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { 
      [self enumerateJSONToFindKeys:obj forKeyNamed:nil]; 
     }]; 
    } 
    else 
    { 
     // If we got here (i.e. it's not a dictionary or array) so its a key/value that we needed 
     NSLog(@"We found key %@ with value %@", keyName, object); 
    } 
} 

A potem chcesz to nazwać jak:

[self enumerateJSONToFindKeys:JSON forKeyNamed:nil]; 

Alternatywnie, jeśli chcesz, aby dana ścieżka kluczowa była zmienna (aby móc do niej pisać za pomocą setValue:forKeyPath:), możesz zrobić coś jak poniżej:

- (void)makeDictionariesMutableForKeyPath:(NSString *)keyPath { 
    NSArray *keys = [keyPath componentsSeparatedByString:@"."]; 

    NSString *currentKeyPath = nil; 
    for (NSString *key in keys) { 
     if (currentKeyPath) { 
      NSString *nextKeyPathAddition = [NSString stringWithFormat:@".%@", key]; 
      currentKeyPath = [currentKeyPath stringByAppendingString:nextKeyPathAddition]; 
     } else { 
      currentKeyPath = key; 
     } 

     id value = [self.mutableDictionary valueForKeyPath:currentKeyPath]; 
     if ([value isKindOfClass:NSDictionary.class]) { 
      NSMutableDictionary *mutableCopy = [(NSDictionary *)value mutableCopy]; 
      [self.mutableDictionary setValue:mutableCopy forKeyPath:currentKeyPath]; 
     } 
    } 

} 
+0

Witam, czy istnieje sposób na odzyskanie wszystkich ketPath? ... coś w stylu "keyname.keyname.keyname" dla wszystkich kluczy sub? – Mike97

+0

... oops ... keypath – Mike97

Powiązane problemy