做iOS開發(fā)的需要學習內存管理躬翁,有一些概念在工作和面試中常常遇到:什么是深拷貝焦蘑,什么是淺拷貝?
mutableCopy
和copy
有什么區(qū)別盒发? 為啥NSString
通常是copy
?感覺網(wǎng)上一些資料講的不是很清楚狡逢,這里說明幾點:
1. 什么是淺拷貝宁舰、深拷貝?
A: 簡單理解就是奢浑,淺拷貝是拷貝了指向對象的指針蛮艰, 深拷貝不但拷貝了對象的指針,還在系統(tǒng)中再分配一塊內存雀彼,存放拷貝對象的內容壤蚜。
2. 如何判斷淺拷貝、深拷貝徊哑?
A: 深淺拷貝取決于拷貝后的對象的是不是和被拷貝對象的地址相同袜刷,如果不同,則產(chǎn)生了新的對象莺丑,則執(zhí)行的是深拷貝著蟹,如果相同,則只是指針拷貝梢莽,相當于retain一次原對象, 執(zhí)行的是淺拷貝.
舉個栗子??
深切拷貝取決于是否為對象分配了新的內存地址萧豆,否則就是指針Copy.
此處上碼:
NSString *str1 = [NSString string];
NSArray *arr1 = [NSArray array];
NSMutableString *mStr1 = [NSMutableString string];
NSMutableArray *mArr1 = [NSMutableArray array];
NSLog(@"-------------這是淺拷貝---未產(chǎn)生新對象----------\n\n");
NSLog(@"-------------不可變對象使用copy------------");
NSString *testStr1 = [str1 copy];
NSArray *testArr1 = [arr1 copy];
NSLog(@"str1: %p, testStr1 : %p", str1, testStr1);
NSLog(@"arr1: %p, testArr1 : %p", arr1, testArr1);
NSLog(@"\n\n");
NSLog(@"-------------這是深拷貝---產(chǎn)生了新對象----------\n\n");
NSLog(@"-----------不可變對象使用mutableCopy----------");
NSMutableString *testmStr1 = [str1 mutableCopy];
NSMutableArray *testmArr1 = [arr1 mutableCopy];
NSLog(@"str1: %p, testmStr1 : %p", str1, testmStr1);
NSLog(@"arr1: %p, testmArr1 : %p", arr1, testmArr1);
NSLog(@"-------------可變對象使用copy-------------");
NSString *testStr2 = [mStr1 copy];
NSArray *testArr2 = [mArr1 copy];
NSLog(@"mStr1: %p, testStr2 : %p", mStr1, testStr2);
NSLog(@"mArr1: %p, testArr2 : %p", mArr1, testArr2);
NSLog(@"-------------可變對象使用mutableCopy-----------");
NSMutableString *testmStr2 = [mStr1 mutableCopy];
NSMutableArray *testmArr2 = [mArr1 mutableCopy];
NSLog(@"mStr1: %p, testmStr2 : %p", mStr1, testmStr2);
NSLog(@"mArr1: %p, testmArr2 : %p", mArr1, testmArr2);
運行結果:
其實常用的Foundation
框架類型,比如NSString
,淺拷貝昏名,也就是木有產(chǎn)生新對象的情況涮雷,只有一種,就是不可變對象使用copy操作轻局,借用網(wǎng)上的一張圖:
其他的比如NSArray
洪鸭、NSDictionary
類似样刷,可以參考 漢斯哈哈哈的文章
3. 為啥NSString
通常用copy
?什么時候用strong
?
A: 因為在使用NSString
的時候卿嘲,一般如果初始化后不想改變這個NSString
的值颂斜,應該將其類型設為copy
,如果用strong
類型拾枣,比如NSString
用NSMutableString
賦值沃疮,指向其地址,當NSMutableString
的值被改變時梅肤,這個NSString
值也發(fā)生了變化司蔬,如果是copy修飾的NSString對象,在用NSMutableString
給他賦值時,會進行深拷貝,即把其內容也給拷貝了一份,兩者指向不同的位置,即使改變了NSMutableString
的值,NSString
的值也不會改變.
參考stackoverflow的問題 NSString property: copy or retain?
Youtube上一個很不錯的視頻說明了這個問題:Why you might use copy instead of strong in an Objective-c @property
上碼:
@property (nonatomic, strong) NSString *aStrongStr;
@property (nonatomic, copy) NSString *aCopyStr;
NSMutableString *mStr = [NSMutableString stringWithString:@"hello"];
self.aStrongStr = mStr;
self.aCopyStr = mStr;
NSLog(@"self.aStrongStr = %@", self.aStrongStr);
NSLog(@"self.aCopyStr = %@", self.aCopyStr);
[mStr appendString:@" world!"];
NSLog(@"self.aStrongStr = %@", self.aStrongStr);
NSLog(@"self.aCopyStr = %@", self.aCopyStr);
4. 還需要注意一點,mutableCopy
返回的是可變對象姨蝴,copy
返回的是不可變對象俊啼。
NSMutableArray *mutableArray = [[NSMutableArray alloc] initWithObjects:@1, @2, nil];
NSMutableArray *array = [mutableArray copy];
[array addObject:@3];
雖然array
定義的是NSMutableArray
, 其實是copy方法返回的一個不可變的數(shù)組,所以在執(zhí)行addObject的方法會報錯左医。
問題:NSString什么時候用copy授帕,什么時候用strong
引用一篇文章: NSString什么時候用copy,什么時候用strong
把一個對象賦值給一個屬性變量浮梢,當這個對象變化了跛十,如果希望屬性變量變化就使用strong屬性,如果希望屬性變量不跟著變化秕硝,就是用copy屬性芥映。
所以,如果一般情況下远豺,我們都不希望字串的值跟著NSMutableString
變化奈偏,所以我們一般用copy
來設置string的屬性。
如果希望字串的值跟著賦值的字串的值變化躯护,可以使用strong
注意:上面的情況是針對于當把 NSMutableString
賦值給NSString
的時候惊来,才會有不同,如果是賦值是NSString
對象榛做,那么使用copy
還是strong
唁盏,結果都是一樣的,因為NSString
對象根本就不能改變自身的值检眯,他是不可變的厘擂。
結論
在集合類對象中,對immutable對象進行copy锰瘸,是指針復制刽严,mutableCopy是內容復制;對mutable對象進行copy和mutableCopy都是內容復制。但是:集合對象的內容復制僅限于對象本身舞萄,對象元素仍然是指針復制眨补。用代碼簡單表示如下:
[immutableObject copy] // 淺復制
[immutableObject mutableCopy] //單層深復制
[mutableObject copy] //單層深復制
[mutableObject mutableCopy] //單層深復制
參考:
- NSString什么時候用copy,什么時候用strong
- NSString屬性什么時候用copy倒脓,什么時候用strong?
- NSString特性分析學習
- iOSInterviewQuestions/《招聘一個靠譜的iOS》面試題參考答案(上).md at master · ChenYilong/iOSInterviewQuestions
如果有誤撑螺,歡迎拍磚~