iOS詳解assign、weak、retain、strong、copy、mutableCopy

先講講assign、retain、strong、weak

  • assign
@property (nonatomic,assign)NSMutableArray *arr;

self.arr = [NSMutableArray array];
[self.arr addObject:@"11"];

//運行結(jié)果:
Thread 1: EXC_BAD_ACCESS 

這里會直接報內(nèi)存錯誤,原因是因為,assign是用來修飾基本數(shù)據(jù)類型的,例如CGFloat、NSInteger、Int、float等等,因為在OC中assign修飾的對象引用計數(shù)不會加+1,這個對象會被立即釋放,而且在釋放之后不會置為nil,會保留對象的指針,會形成野指針,這個時候?qū)ζ浒l(fā)送消息就會崩潰,就會報壞內(nèi)存的錯誤。

  • weak
@property (nonatomic,weak)NSMutableArray *weakArr;

self.weakArr = [NSMutableArray array];
[self.weakArr addObject:@"1"];
NSLog(@"%@",self.weakArr);


//運行結(jié)果:
2018-09-19 16:51:47.901018+0800 Demo[1649:254177] (null)

在OC中Weak用來修飾對象的,如果用來修飾基本數(shù)據(jù)類型會報紅,用weak修飾的對象在引用完畢后會被立即置為nil 而OC向nil發(fā)送消息是不會崩潰的。
這里提一下assign和weak修飾的對象的引用計數(shù)都是不會加1的

  • retain和strong
@property (nonatomic,strong)NSMutableArray *strongArr;

self.strongArr = [NSMutableArray array];
[self.strongArr addObject:@"11"];
NSLog(@"%@",self.strongArr);

//運行結(jié)果:
2018-09-19 16:56:57.389876+0800 Demo[1652:255035] (
    11
)

[NSMutableArray array]這句代碼可以理解為創(chuàng)造了一個對象A,此時A的引用計數(shù)為1,self.strongArr做為對象B,把A賦值給B的時候,A的引用計數(shù)加1,此時A的引用計數(shù)為2,B指向了A,然后編譯器會自動對A進行釋放操作(因為是局部變量),A的引用計數(shù)-1。在擁有B的對象不釋放的時候,A的引用計數(shù)永遠不可能為0,除非你手動釋放或者把B指向一個新的對象,這樣A永遠不會被釋放,這就是所謂的強引用。retain是在MRC中用到的修飾詞,在ARC中便用strong代替了。retain現(xiàn)在同strong,就是指針指向值地址,同時進行引用計數(shù)加1。

因為copy涉及的情況比較多,所以接下來單獨講講copy,主要分為以下幾種情況

在說copy與mutableCopy之前我們先看看官方文檔對深拷貝與淺拷貝的闡釋,如下

深拷貝:
對象拷貝 - 重新申請一片內(nèi)存保留這個對象,與原對象之間沒有半點關(guān)系。

淺拷貝:
指針拷貝 - 實際上相當于引用計數(shù)+1,被拷貝的和拷貝的引用同一個對象。
接下來我們分兩個方面做測試:

  • 非集合不可變對象(copy、mutableCopy)
    NSString *str = [NSString stringWithFormat:@"111"];
    NSString *copyStr = [str copy];
    NSString *mCopyStr = [str mutableCopy];
    NSLog(@"%@ ---- %p",str,str);
    NSLog(@"%@ ---- %p",copyStr,copyStr);
    NSLog(@"%@ ---- %p",mCopyStr,mCopyStr);
    str = @"222";
    NSLog(@"%@ ---- %p",str,str);
    NSLog(@"%@ ---- %p",copyStr,copyStr);
    NSLog(@"%@ ---- %p",mCopyStr,mCopyStr);


//運行結(jié)果:
2018-09-19 17:25:12.102270+0800 Demo[1689:260186] 111 ---- 0xa000000003131313
2018-09-19 17:25:12.102387+0800 Demo[1689:260186] 111 ---- 0xa000000003131313
2018-09-19 17:25:12.102418+0800 Demo[1689:260186] 111 ---- 0x2827aa9d0
2018-09-19 17:25:12.102445+0800 Demo[1689:260186] 222 ---- 0x100776020
2018-09-19 17:25:12.102491+0800 Demo[1689:260186] 111 ---- 0xa000000003131313
2018-09-19 17:25:12.102518+0800 Demo[1689:260186] 111 ---- 0x2827aa9d0

這里我們可以看到str和copyStr的地址是相同的,而mCopyStr是開辟了新的內(nèi)存的。在str = @"222"這句代碼后,因為str是不可變的、不可被修改,所以重新初始化。而這里的copy為淺拷貝,mutableCopy為深拷貝。

  • 非集合可變對象(copy、mutableCopy)
    NSMutableString *mStr = [NSMutableString stringWithFormat:@"111"];
    NSString *copyStr = [mStr copy];
    NSString *mCopyStr = [mStr mutableCopy];
    NSLog(@"%@ ---- %p",mStr,mStr);
    NSLog(@"%@ ---- %p",copyStr,copyStr);
    NSLog(@"%@ ---- %p",mCopyStr,mCopyStr);
    [mStr appendString:@",222"];
    NSLog(@"%@ ---- %p",mStr,mStr);
    NSLog(@"%@ ---- %p",copyStr,copyStr);
    NSLog(@"%@ ---- %p",mCopyStr,mCopyStr);


//運行結(jié)果:
2018-09-19 17:38:08.698067+0800 Demo[1696:261980] 111 ---- 0x2831745a0
2018-09-19 17:38:08.698234+0800 Demo[1696:261980] 111 ---- 0xa000000003131313
2018-09-19 17:38:08.698280+0800 Demo[1696:261980] 111 ---- 0x283174450
2018-09-19 17:38:08.698323+0800 Demo[1696:261980] 111,222 ---- 0x2831745a0
2018-09-19 17:38:08.698391+0800 Demo[1696:261980] 111 ---- 0xa000000003131313
2018-09-19 17:38:08.698432+0800 Demo[1696:261980] 111 ---- 0x283174450

對非集合可變對象進行copy、mutableCopy時,可以看到其內(nèi)存地址都發(fā)生了變化,所以這里的copy、mutableCopy都為深拷貝,對原有mStr操作,不會影響拷貝之后的值。

  • 集合可變對象(copy、mutableCopy)
    NSMutableArray *arrM = [NSMutableArray arrayWithObject:@"11"];
    NSMutableArray *copyArrM = [arrM copy];
    NSMutableArray *mCopyArrM = [arrM mutableCopy];
    NSLog(@"%@ ---- \n%p",arrM,arrM);
    NSLog(@"%@ ---- \n%p",mCopyArrM,mCopyArrM);
    NSLog(@"%@ ---- \n%p",copyArrM,copyArrM);
    [arrM addObject:@"22"];
    NSLog(@"%@ ---- \n%p",arrM,arrM);
    NSLog(@"%@ ---- \n%p",mCopyArrM,mCopyArrM);
    NSLog(@"%@ ---- \n%p",copyArrM,copyArrM);


//運行結(jié)果:
2018-09-19 17:52:49.603180+0800 Demo[1708:264782] (
    11
) ---- 
0x282316d90
2018-09-19 17:52:49.603424+0800 Demo[1708:264782] (
    11
) ---- 
0x282317540
2018-09-19 17:52:49.603533+0800 Demo[1708:264782] (
    11
) ---- 
0x282f4c6a0
2018-09-19 17:52:49.603603+0800 Demo[1708:264782] (
    11,
    22
) ---- 
0x282316d90
2018-09-19 17:52:49.603660+0800 Demo[1708:264782] (
    11
) ---- 
0x282317540
2018-09-19 17:52:49.603716+0800 Demo[1708:264782] (
    11
) ---- 
0x282f4c6a0
  • 集合不可變對象(copy、mutableCopy)
    NSArray *arr = [NSArray arrayWithObject:@"11"];
    NSArray *copyArr = [arr copy];
    NSMutableArray *mCopyArr = [arr mutableCopy];
    NSLog(@"%@ ---- \n%p",arr,arr);
    NSLog(@"%@ ---- \n%p",copyArr,copyArr);
    NSLog(@"%@ ---- \n%p",mCopyArr,mCopyArr);

//運行結(jié)果:
2018-09-19 17:57:24.646701+0800 Demo[1717:266299] (
    11
) ---- 
0x2808b81d0
2018-09-19 17:57:24.646878+0800 Demo[1717:266299] (
    11
) ---- 
0x2808b81d0
2018-09-19 17:57:24.647042+0800 Demo[1717:266299] (
    11
) ---- 
0x2804e1ef0

其實對集合不可變對象、集合可變對象進行copy和mutableCopy結(jié)果可以參考非集合不可變對象、非集合可變對象的結(jié)果

最后對delegate為什么要用weak修飾簡單談下個人的看法

delegate在平常的使用中一般如下:


VC中擁有一個View,那么View的引用計數(shù)+1,而View中有delegate,那么delegate的引用計數(shù)+1。接著我們會在VC中有view.delegate = self,那么如果view用strong修飾,此時引用計數(shù)+1,此時view的引用計數(shù)為2。那么當VC銷毀時,view的引用計數(shù)-1,此時view的引用計數(shù)為1。那么view是無法銷毀的,然后view又引用著delegate,所以view和delegate一直會在內(nèi)存中的。那么如果用weak修飾delegate的,view的引用計數(shù)就為1,等到VC銷毀的時候,view計數(shù)-1,也回跟著銷毀,那么view引用的delegate也會銷毀。
以上是個人的一點愚見,如有錯誤,歡迎大家指正。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容