2013-03-23 16 views
8

Tôi có một số NSDictionary chứa các phiên bản của nhiều loại đối tượng khác nhau (NSArrays, NSDictionaries, NSStrings, NSNumbers, v.v ...). Nhiều người trong số NSDictionariesNSStrings có lồng nhau riêng NSDictionariesNSArrays.Làm thế nào để lặp qua một hệ thống phân cấp lồng nhau của NSDictionaries và NSArrays và chuyển đổi tất cả sang các bản sao có thể thay đổi?

Làm thế nào tôi có thể lặp qua toàn bộ hệ thống cấp bậc, từ trên xuống dưới, và chuyển đổi tất cả các trường hợp của NSDictionariesNSArrays-NSMutableDictionariesNSMutableArrays, tương ứng?

Có bất kỳ chức năng "bản sao có thể thay đổi theo cách đệ quy" dễ dàng nào mà tôi không biết? Nếu không, tôi chỉ cần lặp lại và gõ kiểm tra liên tục? Tôi có thể thay thế khi tôi đi hoặc tôi có xây dựng lại toàn bộ hệ thống phân cấp không?

Trả lời

18

Phương thức sau tạo bản sao có thể thay đổi lồng nhau (sâu) của các mảng lồng nhau, từ điển và tập hợp. Nó cũng có thể được sử dụng để tạo các bản sao có thể thay đổi của các đối tượng không thu thập bên trong cấu trúc phân cấp, chẳng hạn như các chuỗi.

@interface NSObject (MyDeepCopy) 
-(id)deepMutableCopy; 
@end 

@implementation NSObject (MyDeepCopy) 
-(id)deepMutableCopy 
{ 
    if ([self isKindOfClass:[NSArray class]]) { 
     NSArray *oldArray = (NSArray *)self; 
     NSMutableArray *newArray = [NSMutableArray array]; 
     for (id obj in oldArray) { 
      [newArray addObject:[obj deepMutableCopy]]; 
     } 
     return newArray; 
    } else if ([self isKindOfClass:[NSDictionary class]]) { 
     NSDictionary *oldDict = (NSDictionary *)self; 
     NSMutableDictionary *newDict = [NSMutableDictionary dictionary]; 
     for (id obj in oldDict) { 
      [newDict setObject:[oldDict[obj] deepMutableCopy] forKey:obj]; 
     } 
     return newDict; 
    } else if ([self isKindOfClass:[NSSet class]]) { 
     NSSet *oldSet = (NSSet *)self; 
     NSMutableSet *newSet = [NSMutableSet set]; 
     for (id obj in oldSet) { 
      [newSet addObject:[obj deepMutableCopy]]; 
     } 
     return newSet; 
#if MAKE_MUTABLE_COPIES_OF_NONCOLLECTION_OBJECTS 
    } else if ([self conformsToProtocol:@protocol(NSMutableCopying)]) { 
      // e.g. NSString 
     return [self mutableCopy]; 
    } else if ([self conformsToProtocol:@protocol(NSCopying)]) { 
      // e.g. NSNumber 
     return [self copy]; 
#endif 
    } else { 
     return self; 
    } 
} 
@end 

Sử dụng nó như

NSDictionary *dict = ...; 
NSMutableDictionary *mdict = [dict deepMutableCopy]; 

(phím từ điển không được sao chép, chỉ có giá trị).

Tôi khá chắc chắn rằng tôi đã thấy một cái gì đó như thế này trên SO, nhưng không thể tìm thấy nó ngay bây giờ.

+0

Bạn có nghĩa là "khóa không được sao chép"? – zakdances

+1

@yourfriendzak: Đối với một từ điển '@ {key: value}' mã của tôi sẽ tạo '@ {key: mutableCopyOfValue}', chứ không phải '@ {mutableCopyOfKey: mutableCopyOfValue}'. Các phím trong hầu hết các trường hợp là các chuỗi không đổi, do đó không sao chép chúng. –

+0

@yourfriendzak: Thực ra mã này không nhiều hơn bạn yêu cầu. Nó tạo ra các bản sao có thể thay đổi khi có thể, ví dụ như các bản sao có thể thay đổi của các chuỗi trong cấu trúc phân cấp. Nếu không muốn, tôi có thể sửa đổi mã. –

1

Đối với NSDictionary bên ngoài, điều này sẽ tạo ra cho 1 cấp độ xuống.

Bạn cần gọi phương thức này trong một phương thức và tiếp tục nhận tất cả dictarray.

NSMutableDictionary *dict=[NSMutableDictionary new]; 
NSMutableArray *array=[NSMutableArray new]; 

for(NSDictionary *dict in yourMainDictionary){ 
    if([outerDict[dict] class]==[NSDictionary class]){ 
     [dict setObject:outerDict[dict] forKey:dict]; 
    } 
    else if([outerDict[dict] class]==[NSArray class]){ 
     array[array.count]=outerDict[dict]; 
    } 
} 

Không kiểm tra trình biên dịch. Đọc dưới dạng thuật toán

+0

Tại sao không viết thư này làm phương pháp đệ quy? –

2

Trong khi câu trả lời của Anoop là tốt (tôi nghĩ, tôi cũng không biên dịch), nếu hệ thống phân cấp của bạn thực sự là danh sách thuộc tính, bạn có thể sử dụng NSPropertyListSerialization để deserialize plist với container và/hoặc leaf mutable nút.

Điều này sẽ làm giảm ít dòng mã hơn và có thể nhanh hơn dòng gốc thủ công thông qua biểu đồ đối tượng, nhưng giải pháp này chỉ thực sự có ý nghĩa nếu ban đầu bạn deserializing plist từ một nơi nào đó.

+1

NSMutableArray * newArray = (NSMutableArray *) CFBridgingRelease (CFPropertyListCreateDeepCopy (kCFAllocatorDefault, (CFArrayRef) originalArray, kCFPropertyListMutableContainers)); – nh32rg

+1

NSMutableDictionary * newDict = (NSMutableDictionary *) CFBridgingRelease (CFPropertyListCreateDeepCopy (kCFAllocatorDefault, (CFDictionaryRef) originalDict, kCFPropertyListMutableContainers)); – nh32rg

1

Nếu bạn sử dụng một số phương pháp hệ điều hành để tạo từ điển: Các phương pháp này thường có thông số cho phép bạn tạo các đối tượng có thể thay đổi. Ví dụ, lớp serialiser JSON có cờ để làm cho tất cả các từ điển và mảng có thể thay đổi được, và để làm cho tất cả các đối tượng NSString có thể thay đổi được (NSNumber và NSNull không bao giờ có thể thay đổi).

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