深拷貝與淺拷貝;copy與mutableCopy;容器型別的深拷貝;copy和strong;
一、分成三組對比NSMutableDictionary與NSDictionary;NSMutableString與NSString;NSMutableArray與NSArray分別呼叫copy和mutableCopy方法,檢視對應的物件的地址值判斷深淺拷貝;
1、字典:(示例程式碼 testDics方法,有四種組合)
self.mutableDic是NSMutableDictionary型別:
NSMutableDictionary *newMutDic = [self.mutableDic mutableCopy];//深
NSDictionary *newDic = [self.mutableDic copy];//深
self.dic是NSDictionary型別:
NSMutableDictionary *newMutDic = [self.dic mutableCopy];//深
NSDictionary *newDic = [self.dic copy];//淺
2、字串:(示例程式碼 testStrings方法,有四種組合)
self.mutableStr是NSMutableString型別:
NSMutableString *newMutStr = [self.mutableStr mutableCopy];//深
NSString *newStr = [self.mutableStr copy];//深
self.str是NSString型別:
NSMutableString *newMutStr = [self.str mutableCopy];//深
NSString *newStr = [self.str copy];//淺
3、陣列:(示例程式碼 testArrays方法,有四種組合)
self.mutableArray是NSMutableArray型別:
NSMutableArray *newMutArray = [self.mutableArray mutableCopy];//深
NSArray *newArray = [self.mutableArray copy];//深
self.array是NSArray型別:
NSMutableArray *newMutArray = [self.array mutableCopy];//深
NSArray *newArray = [self.array copy];//淺
結論:根據以上1、2、3的程式碼可知,只有NS型別呼叫copy方法才是淺拷貝,其他的情況全是深拷貝
二、容器型別的例項的深拷貝:(示例程式碼testMutableArrayArray方法)
此處以陣列為例,只有在上邊一是陣列深拷貝的情況下為例:
NSMutableArray *newMuArrayArray = [self.mutableArrayArray mutableCopy];
[newMuArrayArray addObject:@[@"44",@"33"]];
[self.adArray addObject:@"3"];
NSArray *ss = newMuArrayArray[0];
NSLog(@"%@ %p == %@ %p == %@ %p == %@ %p",self.mutableArrayArray,self.mutableArrayArray,newMuArrayArray,newMuArrayArray,self.adArray,self.adArray,ss,ss);
上述列印:self.adArray與ss的地址值相同;self.mutableArrayArray與newMuArrayArray地址值不同
結論:容器類(此處以陣列為例)呼叫copy或mutableCopy能出現的深拷貝的情況下,只是容器的深拷貝,而非容器內元素的深拷貝
三、用copy還是strong:(示例程式碼testStrongAndCopyStr方法)
如果你已經完全理解了上述一,這裡就非常好理解了:
宣告屬性為NSString:
@property (nonatomic,strong) NSString *strongString;
@property (nonatomic,copy) NSString *copString;
為屬性賦值:
NSMutableString *oriMuStr = [[NSMutableString alloc] initWithString:@"muStr原始的muStr"];
self.strongString = oriMuStr;
self.copString = oriMuStr;
改變oriMuStr的值:
NSRange r = {3,2};
[oriMuStr replaceCharactersInRange:r withString:@"ooo"];
打log:NSLog(@"\n%@ %@ %@",self.strongString,self.copString,oriMuStr);
屬性為NSString型別時,self.copString沒有隨著oriMuStr的改變而改變,而self.strongString變了。
同理,當屬性為NSMutableString型別時:
宣告屬性:
@property (nonatomic,strong) NSMutableString *strongMutaString;
@property (nonatomic,copy) NSMutableString *copMutaString;
NSMutableString *oriMuStr = [[NSMutableString alloc] initWithString:@"muStr原始的muStr"];
self.strongMutaString = oriMuStr;
self.copMutaString = oriMuStr;
NSRange r = {3,2};
[oriMuStr replaceCharactersInRange:r withString:@"ooo"];
NSLog(@"\n%@ %@ %@",self.strongMutaString,self.copMutaString,oriMuStr);
屬性為NSMutableString型別時,self.copMutaString沒有隨著oriMuStr的改變而改變,而self.strongMutaString變了。
綜上,結論:
無論是宣告NSString還是NSMutableString型別的屬性時,我們希望此屬性被賦值為NSMutableString型別的字串後,此屬性不會因這個可變型別字串的改變而改變(這也是多數情況下的用法),那就用copy修飾屬性
同理、其他相關型別亦是如此。
解析:宣告屬性時用copy和strong其實是重寫了屬性的set方法
例如屬性宣告為copy時的copString屬性的set方法如下:
-(void)setCopString:(NSString *)copString{
_copString = [copString copy];//重寫set方法時,呼叫copy後,即使宣告屬性時不用copy關鍵字(用strong,strong是預設的,所以重寫set方法不加strong也預設是strong的)也有copy的作用
}
當NSString屬性的指標指向NSSMutableString時,其set方法是NSSMutableString的copy根據一中關於string型別的分析可知,此時是深拷貝,故不希望NSString型別的屬性在使用時發生不想要的改變的話,需要copy修飾