2011-12-08 71 views
1

由於Cocoa只爲其內置容器提供淺拷貝,因此我爲自己編寫了自己的DeepCopy類擴展,有時我需要深拷貝。可可容器deepCopy - 如何防止無盡的遞歸?

例如,對於NSArray的它看起來像這樣:

#import "NSArray+CopyDeep.h" 

@implementation NSArray (CopyDeep) 

- (NSArray*) copyDeep 
{ 
    NSMutableArray* retVal = [[NSMutableArray alloc] initWithCapacity:self.count]; 
    for(NSUInteger i=0; i<self.count; i++) 
    { 
     id element = [self objectAtIndex:i]; 
     [retVal addObject:[[element respondsToSelector:@selector(copyDeep)]?[element copyDeep]:[element copy] autorelease]]; 
    } 
    return [[retVal autorelease] copy]; 
} 

- (NSMutableArray*) mutableCopyDeep 
{ 
    NSMutableArray* retVal = [[NSMutableArray alloc] initWithCapacity:self.count]; 
    for(NSUInteger i=0; i<self.count; i++) 
    { 
     id element = [self objectAtIndex:i]; 
     [retVal addObject:[[element respondsToSelector:@selector(mutableCopyDeep)]?[element mutableCopyDeep]:[element mutableCopy] autorelease]]; 
    } 
    return retVal; 
} 

@end 

但現在它已經到了我的注意,還可以加上一個容器實例b到容器實例,並添加a到b。 在這種情況下,在a上調用copyDeep時,這會在b上調用copyDeep時遞歸,這會在a上再次調用它,依此類推:無盡遞歸。

請問你能否給我一些想法,如何輕鬆處理這個問題?

回答

4

如果這些集合中的對象符合NSCoding,那麼你不需要實現自己的深層複製代碼。試試這個:

NSArray *arrayIWantCopied; 
... 

NSArray *clone = [NSUnarchiver unarchiveObjectWithData:[NSKeyedArchiver archivedDataWithRootObject:arrayIWantCopied]]; 

當您使用NSArchiving,編碼到同一對象的多個引用的所有問題都爲您處理。

+0

這是真正實現深度複製IMO的最佳方法。只要每個人都可編碼,框架就會爲你處理。 – Chuck

+0

你不介意有2個內存要求(暫存檔案) –

+0

- 使用NSArchiver和NSUnarchiver或NSKeyedArchiver和NSKeyedUnarchiver,但不要混合NSKeyedArchiver和NSUnarchiver? - 我認爲,可變性保持不變,所以可變(子)對象的副本將是可變的,不可變的將是不可變的? - 因此,整個類擴展實現類將只是: - (id)copyDeep { \t return [NSUnarchiver unarchiveObjectWithData:[NSArchiver encodeRootObject:self]]; } ? - 所以我想,我也可以將它添加到所有受支持(但不支持)類的基類中以減少冗餘? – Kaiserludi

1

與沿線的方法實現實際的複製:

- (NSArray *)copyDeepWithAncestors:(NSDictionary *)ancestorMapping; 

ancestorMapping加入您遇到深可複製對象作爲鍵,與副本作爲相應的值。如果遇到已經存在的對象,只需使用已創建的副本進行替換,而不是再次遞歸。 (您可能需要將字典創建爲CFDictionary以避開NSDictionary的主要限制,但它們是toll-free bridged,因此,您仍然可以在創建它時將它用作NSDictionary。)

+0

很酷的想法。 – Almo