先講講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也會銷毀。以上是個人的一點愚見,如有錯誤,歡迎大家指正。