Object c mutableCopy

Apple官方文檔如下:https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/Collections/Articles/Copying.html

最近用Core Data做數據管理,Fetch到NSArray類型的結果數組,爲了能夠進行增、刪、改,我把它MutableCopy到一個NSMutableArray數組中。增加、刪除用manageModelsContext中的接口操作即可,修改則把NSArray結果中需要修改的實例取出來進行更改,然後用manageModelsContext保存即可完成修改到sqlite文件。

可是問題是我發現用MutableCopy得到的數組中取出的元素直接修改後保存,也能完成修改操作。於是就產生了這樣的一個疑問:MutableCopy是淺拷貝??再下來我就發現copy相關的東西我還完全沒有搞清楚。

 

首先關於copy和mutableCopy的行爲:不管是NSString這種元素類、還是NSArray這樣的容器類、還是Mutable和非Mutable類,copy和mutableCopy調用後表現的行爲到底是什麼樣完成取決於類本身NSCopying和NSMutableCopying協議是如何實現的。

想要正常調用copy和mutableCopy兩個函數,那麼類就一定要實現對應的協議。

1.      元素數據的copy和mutableCopy。

常用的NSString類,示例代碼如下:


[cpp] view plaincopy


  1. NSString* string = @”a”;  
  2. NSString* stringCopy = [string copy];// stringCopy與string地址相同,retainCount+ 1   
  3. NSMutableString* stringMCopy = [string mutablecopy];// stringMCopy與string地址不同   
  4.    
  5. NSMutableString* stringM1 = [stringMCopy copy];//地址與stringMCopy不同,且爲不可修改   
  6. NSMutableString* stringM2 = [stringMCopy mutablecopy];//地址與stringMCopy不同,可修改   

[cpp] view plaincopy


  1. NSString* string = @”a”;  
  2. NSString* stringCopy = [string copy];// stringCopy與string地址相同,retainCount+ 1  
  3. NSMutableString* stringMCopy = [string mutablecopy];// stringMCopy與string地址不同  
  4.    
  5. NSMutableString* stringM1 = [stringMCopy copy];//地址與stringMCopy不同,且爲不可修改  
  6. NSMutableString* stringM2 = [stringMCopy mutablecopy];//地址與stringMCopy不同,可修改   




可以基本推出NSString和NSMutableString中兩個協議的實現

 

[cpp] view plaincopy


  1. NSString:  
  2. - (id)copywithZone:(NSZone*)zone  
  3. {  
  4.   return self;  
  5. }  
  6.    
  7. - (id)mutableCopywithZone:(NSZone*)zone  
  8. {  
  9.   NSMutableString* copy =[[NSMutableString alloc] initxxxxxx];  
  10.   ....  
  11.   return copy;  
  12. }  
  13. NSMutableString:  
  14. - (id)copywithZone:(NSZone*)zone  
  15. {  
  16.   NSString* copy = [[NSStringalloc] initxxxxxx];  
  17.   ....  
  18.   return copy;//所以不可修改   
  19. }  
  20.    
  21. - (id)mutableCopywithZone:(NSZone*)zone  
  22. {  
  23.   NSMutableString* copy =[[NSMutableString alloc] initxxxxxx];  
  24.   ....  
  25.   return copy;  
  26. }  

[cpp] view plaincopy


  1. NSString:  
  2. - (id)copywithZone:(NSZone*)zone  
  3. {  
  4.   return self;  
  5. }  
  6.    
  7. - (id)mutableCopywithZone:(NSZone*)zone  
  8. {  
  9.   NSMutableString* copy =[[NSMutableString alloc] initxxxxxx];  
  10.   ....  
  11.   return copy;  
  12. }  
  13. NSMutableString:  
  14. - (id)copywithZone:(NSZone*)zone  
  15. {  
  16.   NSString* copy = [[NSStringalloc] initxxxxxx];  
  17.   ....  
  18.   return copy;//所以不可修改  
  19. }  
  20.    
  21. - (id)mutableCopywithZone:(NSZone*)zone  
  22. {  
  23.   NSMutableString* copy =[[NSMutableString alloc] initxxxxxx];  
  24.   ....  
  25.   return copy;  
  26. }  





2.      容器類的copy和mutableCopy。

常用類NSArray和NSMutableArray,看如下示例代碼:


[cpp] view plaincopy


  1. Class1* obj1= ....;//正常初始化   
  2. NSArray* array = [[NSArray alloc] initWithObjects:obj1, nil];  
  3. NSArray* arrayCopy = [array copy];//地址不變,retaincount+1   
  4. NSMutableArray* arrayMCopy = [array mutableCopy];//地址改變,但是數組中成員指針和obj1相同,淺拷貝   
  5.   
  6. NSMutableArray* arrayM1 = [arrayMCopy Copy];//地址改變,但是數組中成員指針和obj1相同,淺拷貝。arrayM1爲NSArray不可修改   
  7. NSMutableArray* arrayM2 = [arrayMCopy mutableCopy];//地址改變,但是數組中成員指針和obj1相同,淺拷貝  

[cpp] view plaincopy


  1. Class1* obj1= ....;//正常初始化  
  2. NSArray* array = [[NSArray alloc] initWithObjects:obj1, nil];  
  3. NSArray* arrayCopy = [array copy];//地址不變,retaincount+1  
  4. NSMutableArray* arrayMCopy = [array mutableCopy];//地址改變,但是數組中成員指針和obj1相同,淺拷貝  
  5.   
  6. NSMutableArray* arrayM1 = [arrayMCopy Copy];//地址改變,但是數組中成員指針和obj1相同,淺拷貝。arrayM1爲NSArray不可修改  
  7. NSMutableArray* arrayM2 = [arrayMCopy mutableCopy];//地址改變,但是數組中成員指針和obj1相同,淺拷貝  

[cpp] view plaincopy


  1. //推斷  

[cpp] view plaincopy


  1. //推斷  

[cpp] view plaincopy


  1. NSArray:  
  2. - (id)copywithZone:(NSZone*)zone  
  3. {  
  4.   //僞碼   
  5.   return [self retain];  
  6. }  
  7.   
  8. - (id)mutableCopywithZone:(NSZone*)zone  
  9. {  
  10.   NSMutableArray* copy = [[NSMutableString alloc] initxxxxxx];  
  11.   for (id element in self) {  
  12.     [copy addObject:element];//element retian count + 1   
  13.     ....  
  14.   }  
  15.   return copy;  
  16. }  
  17.   
  18. NSMutableArray:  
  19. - (id)copywithZone:(NSZone*)zone  
  20. {  
  21.   NSArray* copy = [[NSArray alloc] initXXX];  
  22.   /*把每個element加入到copy數組,retainCount+1*/  
  23.   ....  
  24.   return copy;  
  25. }  
  26.   
  27. - (id)mutableCopywithZone:(NSZone*)zone  
  28. {  
  29.   NSMutableArray* copy = [[NSMutableString alloc] initxxxxxx];  
  30.   for (id element in self) {  
  31.     [copy addObject:element];//element retian count + 1   
  32.     ....  
  33.   }  
  34.   return copy;  
  35. }  

[cpp] view plaincopy


  1. NSArray:  
  2. - (id)copywithZone:(NSZone*)zone  
  3. {  
  4.   //僞碼  
  5.   return [self retain];  
  6. }  
  7.   
  8. - (id)mutableCopywithZone:(NSZone*)zone  
  9. {  
  10.   NSMutableArray* copy = [[NSMutableString alloc] initxxxxxx];  
  11.   for (id element in self) {  
  12.     [copy addObject:element];//element retian count + 1  
  13.     ....  
  14.   }  
  15.   return copy;  
  16. }  
  17.   
  18. NSMutableArray:  
  19. - (id)copywithZone:(NSZone*)zone  
  20. {  
  21.   NSArray* copy = [[NSArray alloc] initXXX];  
  22.   /*把每個element加入到copy數組,retainCount+1*/  
  23.   ....  
  24.   return copy;  
  25. }  
  26.   
  27. - (id)mutableCopywithZone:(NSZone*)zone  
  28. {  
  29.   NSMutableArray* copy = [[NSMutableString alloc] initxxxxxx];  
  30.   for (id element in self) {  
  31.     [copy addObject:element];//element retian count + 1  
  32.     ....  
  33.   }  
  34.   return copy;  
  35. }  





3.      深拷貝

上面提到的官方文檔中介紹兩種實現深拷貝的方法:

a.      用Array的initWithArray:  copyItems函數,如下:

NSArray *deepCopyArray=[[NSArray alloc] initWithArray: someArraycopyItems: YES];

調用後,會對原NSArray中的每個元素調用其copy函數,並把返回的id加入到新的數組中。所以這是依賴於Obj對象類實現的深拷貝,如果- (id)copywithZone:(NSZone*)zone是重新分配一塊內存賦值後返回,那麼就是真正的深拷貝。如果直接返回自身,那麼它只是淺拷貝。

b.      用archiver方式:

NSArray* trueDeepCopyArray = [NSKeyedUnarchiverunarchiveObjectWithData: [NSKeyedArchiver archivedDataWithRootObject:oldArray]];

這是真正意義上的深拷貝,不依賴於實際類Copying協議的實現。

 

4. 用Category實現自定義的深拷貝deepmutableCopy,如:


[cpp] view plaincopy


  1. - (NSMutableArray *)mutableDeepCopy  
  2. {  
  3.     NSMutableArray *ret = [[NSMutableArrayalloc] initWithCapacity:[self count]];  
  4.     for (id value in self)  
  5.     {  
  6.         id oneCopy = nil;  
  7.         if ([value respondsToSelector:@selector(mutableDeepCopy)])  
  8.             oneCopy = [value mutableDeepCopy];  
  9.         else if ([value respondsToSelector:@selector(mutableCopy)])  
  10.             oneCopy = [value mutableCopy];  
  11.         if (oneCopy == nil)  
  12.             oneCopy = [value copy];  
  13.         [ret addObject: oneCopy];  
  14.     }  
  15.     return ret;  
  16. }  

[cpp] view plaincopy


  1. - (NSMutableArray *)mutableDeepCopy  
  2. {  
  3.     NSMutableArray *ret = [[NSMutableArrayalloc] initWithCapacity:[self count]];  
  4.     for (id value in self)  
  5.     {  
  6.         id oneCopy = nil;  
  7.         if ([value respondsToSelector:@selector(mutableDeepCopy)])  
  8.             oneCopy = [value mutableDeepCopy];  
  9.         else if ([value respondsToSelector:@selector(mutableCopy)])  
  10.             oneCopy = [value mutableCopy];  
  11.         if (oneCopy == nil)  
  12.             oneCopy = [value copy];  
  13.         [ret addObject: oneCopy];  
  14.     }  
  15.     return ret;  
  16. }  
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章