先講講assign、retain、strong、weak
- assign
@property (nonatomic,assign)NSMutableArray *arr;
self.arr = [NSMutableArray array];
[self.arr addObject:@"11"];
//運(yùn)行結(jié)果:
Thread 1: EXC_BAD_ACCESS
這里會(huì)直接報(bào)內(nèi)存錯(cuò)誤,原因是因?yàn)椋琣ssign是用來修飾基本數(shù)據(jù)類型的,例如CGFloat、NSInteger、Int、float等等,因?yàn)樵贠C中assign修飾的對象引用計(jì)數(shù)不會(huì)加+1,這個(gè)對象會(huì)被立即釋放,而且在釋放之后不會(huì)置為nil,會(huì)保留對象的指針,會(huì)形成野指針,這個(gè)時(shí)候?qū)ζ浒l(fā)送消息就會(huì)崩潰,就會(huì)報(bào)壞內(nèi)存的錯(cuò)誤。
- weak
@property (nonatomic,weak)NSMutableArray *weakArr;
self.weakArr = [NSMutableArray array];
[self.weakArr addObject:@"1"];
NSLog(@"%@",self.weakArr);
//運(yùn)行結(jié)果:
2018-09-19 16:51:47.901018+0800 Demo[1649:254177] (null)
在OC中Weak用來修飾對象的,如果用來修飾基本數(shù)據(jù)類型會(huì)報(bào)紅,用weak修飾的對象在引用完畢后會(huì)被立即置為nil 而OC向nil發(fā)送消息是不會(huì)崩潰的。
這里提一下assign和weak修飾的對象的引用計(jì)數(shù)都是不會(huì)加1的
- retain和strong
@property (nonatomic,strong)NSMutableArray *strongArr;
self.strongArr = [NSMutableArray array];
[self.strongArr addObject:@"11"];
NSLog(@"%@",self.strongArr);
//運(yùn)行結(jié)果:
2018-09-19 16:56:57.389876+0800 Demo[1652:255035] (
11
)
[NSMutableArray array]這句代碼可以理解為創(chuàng)造了一個(gè)對象A,此時(shí)A的引用計(jì)數(shù)為1,self.strongArr做為對象B,把A賦值給B的時(shí)候,A的引用計(jì)數(shù)加1,此時(shí)A的引用計(jì)數(shù)為2,B指向了A,然后編譯器會(huì)自動(dòng)對A進(jìn)行釋放操作(因?yàn)槭蔷植孔兞?,A的引用計(jì)數(shù)-1。在擁有B的對象不釋放的時(shí)候,A的引用計(jì)數(shù)永遠(yuǎn)不可能為0,除非你手動(dòng)釋放或者把B指向一個(gè)新的對象,這樣A永遠(yuǎn)不會(huì)被釋放,這就是所謂的強(qiáng)引用。retain是在MRC中用到的修飾詞,在ARC中便用strong代替了。retain現(xiàn)在同strong,就是指針指向值地址,同時(shí)進(jìn)行引用計(jì)數(shù)加1。
因?yàn)閏opy涉及的情況比較多,所以接下來單獨(dú)講講copy,主要分為以下幾種情況
在說copy與mutableCopy之前我們先看看官方文檔對深拷貝與淺拷貝的闡釋,如下

深拷貝:
對象拷貝 - 重新申請一片內(nèi)存保留這個(gè)對象,與原對象之間沒有半點(diǎn)關(guān)系。
淺拷貝:
指針拷貝 - 實(shí)際上相當(dāng)于引用計(jì)數(shù)+1,被拷貝的和拷貝的引用同一個(gè)對象。
接下來我們分兩個(gè)方面做測試:
- 非集合不可變對象(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);
//運(yùn)行結(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"這句代碼后,因?yàn)閟tr是不可變的、不可被修改,所以重新初始化。而這里的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);
//運(yùn)行結(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
對非集合可變對象進(jìn)行copy、mutableCopy時(shí),可以看到其內(nèi)存地址都發(fā)生了變化,所以這里的copy、mutableCopy都為深拷貝,對原有mStr操作,不會(huì)影響拷貝之后的值。
- 集合可變對象(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);
//運(yùn)行結(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);
//運(yùn)行結(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
其實(shí)對集合不可變對象、集合可變對象進(jìn)行copy和mutableCopy結(jié)果可以參考非集合不可變對象、非集合可變對象的結(jié)果
最后對delegate為什么要用weak修飾簡單談下個(gè)人的看法
delegate在平常的使用中一般如下:

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