2012-02-08 30 views
13

Có ai đã thực hiện tra cứu trật tự đệ quy của một NSDictionary cấu trúc không xác định không? Tôi muốn lấy bất kỳ NSDictionary và xử lý từng cấp theo thứ tự phân cấp.Theo dõi đệ quy NSDictionary của cấu trúc không xác định

1) Dữ liệu này đến từ JSON được xác thực. Có an toàn khi nói rằng NSDictionary được tạo ra từ một khung công tác như SBJSON (JSON Framework) sẽ chỉ dẫn đến kết hợp các từ điển lồng nhau, mảng và các lá tùy ý?

2) Làm cách nào để có thể thực hiện tra cứu chung bằng cách sử dụng liệt kê nhanh hoạt động cho cả mảng và từ điển? Với mã bên dưới, khi tôi truy cập từ điển trong một mảng, nó sẽ dừng ngang qua. Tuy nhiên, nếu tôi tiếp tục đệ quy trong điều kiện mảng (để kiểm tra các từ điển trong mảng), nó sẽ chuyển tiếp lần lặp tiếp theo của id value = [dict valueForKey:key]; bằng một S23ABAYN -[__NSCFDictionary length]: unrecognized selector sent to instance. Tôi không biết tại sao điều này lại là một vấn đề, bởi vì tôi đã vượt qua dòng đó với một từ điển cấp cao nhất (nơi mà các từ điển cấp phụ đã được tìm thấy).

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

Rất cám ơn

+0

Bạn làm điều này mỗi khi bạn NSLog một NSDictionary. –

+0

Đúng, nhưng điểm chung là nắm bắt và xử lý các đối tượng lồng nhau trong quá trình, không chỉ đăng nhập chúng. –

+0

Bạn chỉ cần học cách sử dụng 'isKindOfClass'. –

Trả lời

31

tôi đã thực hiện một cái gì đó tương tự như nơi tôi sẽ đi qua một cấu trúc đối tượng JSON đến từ một dịch vụ web và chuyển đổi từng phần tử vào một phiên bản có thể thay đổi.

- (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

Tuyệt vời. Tôi sẽ cung cấp cho một shot và báo cáo lại. –

+0

Làm việc như một sự quyến rũ! Tôi thích cách bạn tính toán nó ra một phương pháp một param, do đó, người gọi không cần phải biết params tối nghĩa. –

+0

Tại sao bạn vượt qua "cha mẹ"? Có vẻ như nó chưa từng được sử dụng. –

4

tôi cần phải biết tên chủ chốt cho các giá trị vì vậy tôi viết lại những gì đã Joel và đến với điều này:

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

Và sau đó bạn muốn gọi nó là thích:

[self enumerateJSONToFindKeys:JSON forKeyNamed:nil]; 

Hoặc, nếu bạn muốn tạo một đường dẫn khóa cụ thể có thể thay đổi được (để bạn có thể viết lại bằng cách sử dụng setValue:forKeyPath:), bạn có thể thực hiện một số như sau:

- (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

Xin chào, có cách nào để trả lại tất cả ketPath không? ... một cái gì đó như "keyname.keyname.keyname" cho tất cả các khóa phụ ?? – Mike97

+0

... oops ... keypath – Mike97

Các vấn đề liên quan