本文邏輯圖:
在知道他們區(qū)別之前勋篓,我們首先要知道NSObject對(duì)象的賦值操作做了哪些操作吧享。
A=C其實(shí)是在內(nèi)存中創(chuàng)建了一個(gè)A,然后又開辟了一個(gè)內(nèi)存C譬嚣,C里面存放的著值B钢颂。
如下:
NSMutableString*tempMStr = [[NSMutableString alloc]initWithString:@"strValue"];
NSLog(@"tempMStr值地址:%p,tempMStr值%@,tempMStr值引用計(jì)數(shù)%@\\n", tempMStr,tempMStr,[tempMStr valueForKey:@"retainCount"]);
//輸出tempMStr值地址:0x7a05f650拜银,tempMStr值strValue,tempMStr值引用計(jì)數(shù)1
此處tempMStr就是A殊鞭,值地址就是C,“strValue”就是B尼桶,而引用計(jì)數(shù)這個(gè)概念是針對(duì)C的操灿,賦值給其他變量或者指針設(shè)置為nil,如tempStr = nil泵督,都會(huì)使得引用計(jì)數(shù)有所增減趾盐。當(dāng)內(nèi)存區(qū)域引用計(jì)數(shù)為0時(shí)就會(huì)將數(shù)據(jù)抹除。而我們使用copy,strong,retain,weak,assign區(qū)別就在:
1.是否開辟新的內(nèi)存
2.是否對(duì)地址C有引用計(jì)數(shù)增加
需要注意的是property修飾符是在被賦值時(shí)起作用幌蚊。
1.以典型的NSMutableString為例
@property(copy,nonatomic)NSMutableString*aCopyMStr;
@property(strong,nonatomic)NSMutableString*strongMStr;
@property(weak,nonatomic)NSMutableString*weakMStr;
@property(assign,nonatomic)NSMutableString*assignMStr;
NSMutableString*mstrOrigin = [[NSMutableStringalloc]initWithString:@"mstrOriginValue"];
self.aCopyMStr= mstrOrigin;
self.strongMStr= mstrOrigin;
self.strongMStr= mstrOrigin;
self.weakMStr= mstrOrigin;
NSLog(@"mstrOrigin輸出:%p,%@\\n", mstrOrigin,mstrOrigin);
NSLog(@"aCopyMStr輸出:%p,%@\\n",_aCopyMStr,_aCopyMStr);
NSLog(@"strongMStr輸出:%p,%@\\n",_strongMStr,_strongMStr);
NSLog(@"weakMStr輸出:%p,%@\\n",_weakMStr,_weakMStr);
NSLog(@"引用計(jì)數(shù)%@",[mstrOriginvalueForKey:@"retainCount"]);
//輸出結(jié)果
//2016-09-01 15:19:13.134 lbCopy[1205:87583] mstrOrigin輸出:0x7892a5e0,mstrOriginValue
//2016-09-01 15:19:13.135 lbCopy[1205:87583] aCopyMStr輸出:0x7893deb0,mstrOriginValue
//2016-09-01 15:19:13.135 lbCopy[1205:87583] strongMStr輸出:0x7892a5e0,mstrOriginValue
//2016-09-01 15:19:13.135 lbCopy[1205:87583] weakMStr輸出:0x7892a5e0,mstrOriginValue
//2016-09-01 15:19:13.135 lbCopy[1205:87583] 引用計(jì)數(shù)2
strongMStr和weakMStr指針指向的內(nèi)存地址都和mstrOrigin相同,但mstrOrigin內(nèi)存引用計(jì)數(shù)為2谤碳,不為3,因?yàn)閣eakMStr雖然指向了數(shù)據(jù)內(nèi)存地址(之后用C簡(jiǎn)稱溢豆,見示意圖1),但不會(huì)增加C計(jì)數(shù)瘸羡。copy修飾的的aCopyMStr漩仙,賦值后則是自己?jiǎn)为?dú)開辟了一塊內(nèi)存,內(nèi)存上保存“mstrOrigin”字符串犹赖,并指向队他。
拷貝示意圖如下
可見當(dāng)我修改mstrOrigin的值的時(shí)候,必然不會(huì)影響aCopyMStr,只會(huì)影響strongMStr和weakMStr峻村。我們來驗(yàn)證下
NSLog(@"------------------修改原值后------------------------");
[mstrOriginappendString:@"1"];
NSLog(@"mstrOrigin輸出:%p,%@\\n", mstrOrigin,mstrOrigin);
NSLog(@"aCopyMStr輸出:%p,%@\\n",_aCopyMStr,_aCopyMStr);
NSLog(@"strongMStr輸出:%p,%@\\n",_strongMStr,_strongMStr);
NSLog(@"weakMStr輸出:%p,%@\\n",_weakMStr,_weakMStr);
//輸出結(jié)果
//2016-09-01 15:33:02.839 lbCopy[1205:87583] mstrOrigin輸出:0x7892a5e0,mstrOrigin1
//2016-09-01 15:33:02.839 lbCopy[1205:87583] aCopyMStr輸出:0x7893deb0,mstrOrigin
//2016-09-01 15:33:02.839 lbCopy[1205:87583] strongMStr輸出:0x7892a5e0,mstrOrigin1
//2016-09-01 15:33:02.839 lbCopy[1205:87583] weakMStr輸出:0x7892a5e0,mstrOrigin1
copy會(huì)重新開辟新的內(nèi)存來保存一份相同的數(shù)據(jù)麸折。被賦值對(duì)象和原值修改互不影響。strong和weak賦值都指向原來數(shù)據(jù)地址粘昨,區(qū)別是前者會(huì)對(duì)數(shù)據(jù)地址進(jìn)行引用計(jì)數(shù)+1垢啼,后者不會(huì)
引用計(jì)數(shù)是否+1有什么實(shí)質(zhì)區(qū)別呢窜锯?
如果知道“值地址的引用計(jì)數(shù)為0時(shí),地址上保存的值就會(huì)被釋放”芭析。那么區(qū)別就不難理解锚扎,weak修飾的指針A指向的值地址C,那么地址上當(dāng)其他指向他的指針被釋放的時(shí)候馁启,這個(gè)值地址引用計(jì)數(shù)也就變?yōu)?了驾孔,這個(gè)A的值也就為nil了。換句話說當(dāng)值地址C上沒有其他強(qiáng)引用指針修飾的時(shí)候C就會(huì)被立即釋放惯疙,A的值就變?yōu)閚il了翠勉。
這里我們來初始化mstrOrigin和并將strongMStr設(shè)置為nil讓C的引用計(jì)數(shù)為0,然后輸出weakMStr霉颠,看是否為nil.
注:初始化和設(shè)為nil都可以將指針?biāo)赶虻臄?shù)據(jù)地址引用計(jì)數(shù)減少1
mstrOrigin = [[NSMutableStringalloc]initWithString:@"mstrOriginChange2"];
self.strongMStr=nil;
NSLog(@"mstrOrigin輸出:%p,%@\\n", mstrOrigin,mstrOrigin);
NSLog(@"strongMStr輸出:%p,%@\\n",_strongMStr,_strongMStr);
NSLog(@"weakMStr輸出:%p,%@\\n",_weakMStr,_weakMStr);
輸出結(jié)果
//2016-09-01 15:41:33.793 lbCopy[1247:100742] mstrOrigin輸出:0x7874d140,mstrOriginChange2
//2016-09-01 15:41:33.793 lbCopy[1247:100742] strongMStr輸出:0x0,(null)
//2016-09-01 15:41:33.794 lbCopy[1247:100742] weakMStr輸出:0x0,(null)
可見之前引用計(jì)數(shù)2是mstrOrigin和strongMStr添加的对碌。
結(jié)論:copy會(huì)重新開辟新的內(nèi)存來保存一份相同的數(shù)據(jù)。被賦值對(duì)象和原值修改互不影響掉分。strong和weak雖然都指向原來數(shù)據(jù)地址俭缓,原值修改的時(shí)候storng和weak會(huì)隨之變化。區(qū)別是前者會(huì)對(duì)數(shù)據(jù)地址進(jìn)行引用計(jì)數(shù)+1防止原地址值被釋放酥郭,但后者不會(huì)华坦,當(dāng)其他值都不在指向值地址時(shí),值地址被釋放不从,weak的值也就是為nil了惜姐。我們稱會(huì)對(duì)數(shù)據(jù)地址增加引用計(jì)數(shù)的為強(qiáng)引用,不改變引用計(jì)數(shù)的為弱引用
1.2 assign和weak的區(qū)別
對(duì)assign和weak修飾的值進(jìn)行賦值椿息,并輸出指針結(jié)構(gòu)地址和值
self.assignMStr= mstrOrigin;
self.weakMStr= mstrOrigin;
mstrOrigin = [[NSMutableStringalloc]initWithString:@"mstrOriginChange3"];
NSLog(@"weakMStr輸出:%p,%@\\n",_weakMStr,_weakMStr);
NSLog(@"assignMStr輸出:%p,%@\\n",self.assignMStr,self.assignMStr);
可以發(fā)現(xiàn)在輸出assignMStr時(shí)會(huì)偶爾出現(xiàn)奔潰的情況歹袁。原因是發(fā)送了野指針的情況。assign同weak寝优,指向C并且計(jì)數(shù)不+1条舔,但當(dāng)C地址引用計(jì)數(shù)為0時(shí),assign不會(huì)對(duì)C地址進(jìn)行B數(shù)據(jù)的抹除操作乏矾,只是進(jìn)行值釋放孟抗。這就導(dǎo)致野指針存在,即當(dāng)這塊地址還沒寫上其他值前钻心,能輸出正常值凄硼,但一旦重新寫上數(shù)據(jù),該指針隨時(shí)可能沒有值捷沸,造成奔潰摊沉。
1.3那retain是什么
ARC之前屬性構(gòu)造器的關(guān)鍵字是retain,copy,assign,strong和weak是ARC帶出來的關(guān)鍵字痒给。
retain現(xiàn)在同strong说墨,就是指針指向值地址骏全,同時(shí)進(jìn)行引用計(jì)數(shù)加1。
2.非NSMutableString的情況
<br />
上面我們討論了典型的例子NSMutableString婉刀,即非容器可變變量吟温。也就是說還存在其他三種類型需要討論...
1.非容器不可變變量NSSting
2.容器可變變量NSMutableArray
3.容器不可變變量NSArray
更重要的是不同類型會(huì)有不同結(jié)果...,好吧突颊,不要奔潰鲁豪,上面一大段我們討論了1/4,接下來我們要討論其他的3/4情況律秃。但好消息是爬橡,其他幾種情況基本與上面非容器可變變量情況基本類似。
2.1容器可變變量
容器可變變量的典型例子就是NSMutableArray
下面代碼可以忽略棒动,只做參考用
@property(copy,nonatomic)NSMutableArray*aCopyMArr;
@property(strong,nonatomic)NSMutableArray*strongMArr;
@property(weak,nonatomic)NSMutableArray*weakMArr;
NSMutableArray*mArrOrigin = [[NSMutableArrayalloc]init];
NSMutableString*mstr1 = [[NSMutableStringalloc]initWithString:@"value1"];
NSMutableString*mstr2 = [[NSMutableStringalloc]initWithString:@"value2"];
NSMutableString*mstr3 = [[NSMutableStringalloc]initWithString:@"value3"];
[mArrOriginaddObject:mstr1];
[mArrOriginaddObject:mstr2];
//將mArrOrigin拷貝給aCopyMArr糙申,strongMArr,weakMArr
self.aCopyMArr= mArrOrigin;
self.strongMArr= mArrOrigin;
self.weakMArr= mArrOrigin;
NSLog(@"mArrOrigin輸出:%p,%@\\n", mArrOrigin,mArrOrigin);
NSLog(@"aCopyMArr輸出:%p,%@\\n",_aCopyMArr,_aCopyMArr);
NSLog(@"strongMArr輸出:%p,%@\\n",_strongMArr,_strongMArr);
NSLog(@"weakMArr輸出:%p,%@\\n",_weakMArr,_weakMArr);
NSLog(@"weakMArr輸出:%p,%@\\n",_weakMArr[0],_weakMArr[0]);
NSLog(@"mArrOrigin中的數(shù)據(jù)引用計(jì)數(shù)%@", [mArrOriginvalueForKey:@"retainCount"]);
NSLog(@"%p %p %p %p",&mArrOrigin,mArrOrigin,mArrOrigin[0],mArrOrigin[1]);
//以下是輸出
2016-09-02 20:42:30.777 lbCopy[4207:475091] mArrOrigin輸出:0x78f81680,(
value1,
value2
)
2016-09-02 20:42:30.777 lbCopy[4207:475091] aCopyMArr輸出:0x7a041340,(
value1,
value2
)
2016-09-02 20:42:30.777 lbCopy[4207:475091] strongMArr輸出:0x78f81680,(
value1,
value2
)
2016-09-02 20:42:30.777 lbCopy[4207:475091] weakMArr輸出:0x78f81680,(
value1,
value2
)
2016-09-02 20:42:30.777 lbCopy[4207:475091] weakMArr輸出:0x78f816a0,value1
2016-09-02 20:42:30.778 lbCopy[4207:475091] mArrOrigin中的數(shù)據(jù)引用計(jì)數(shù)(
3,
3
)
2016-09-02 20:42:30.778 lbCopy[4207:475091] 0xbffb4098 0x78f81680 0x78f816a0 0x78f81710
//以上是輸出
//給原數(shù)組添加一個(gè)元素
[mArrOriginaddObject:mstr3];
NSLog(@"mArrOrigin輸出:%p,%@\\n", mArrOrigin,mArrOrigin);
NSLog(@"aCopyMArr輸出:%p,%@\\n",_aCopyMArr,_aCopyMArr);
NSLog(@"strongMArr輸出:%p,%@\\n",_strongMArr,_strongMArr);
NSLog(@"weakMArr輸出:%p,%@\\n",_weakMArr,_weakMArr);
NSLog(@"mArrOrigin中的數(shù)據(jù)引用計(jì)數(shù)%@", [mArrOriginvalueForKey:@"retainCount"]);
//修改原數(shù)組中的元素船惨,看是否有隨之變化
[mstr1appendFormat:@"aaa"];
NSLog(@"mArrOrigin輸出:%p,%@\\n", mArrOrigin,mArrOrigin);
NSLog(@"aCopyMArr輸出:%p,%@\\n",_aCopyMArr,_aCopyMArr);
NSLog(@"strongMArr輸出:%p,%@\\n",_strongMArr,_strongMArr);
NSLog(@"weakMArr輸出:%p,%@\\n",_weakMArr,_weakMArr);
//以下是輸出
2016-09-02 20:42:30.778 lbCopy[4207:475091] mArrOrigin輸出:0x78f81680,(
value1,
value2,
value3
)
2016-09-02 20:42:30.778 lbCopy[4207:475091] aCopyMArr輸出:0x7a041340,(
value1,
value2
)
2016-09-02 20:42:30.778 lbCopy[4207:475091] strongMArr輸出:0x78f81680,(
value1,
value2,
value3
)
2016-09-02 20:42:30.778 lbCopy[4207:475091] weakMArr輸出:0x78f81680,(
value1,
value2,
value3
)
2016-09-02 20:42:30.779 lbCopy[4207:475091] mArrOrigin中的數(shù)據(jù)引用計(jì)數(shù)(
3,
3,
2
)
2016-09-02 20:42:30.779 lbCopy[4207:475091] mArrOrigin輸出:0x78f81680,(
value1aaa,
value2,
value3
)
2016-09-02 20:42:30.779 lbCopy[4207:475091] aCopyMArr輸出:0x7a041340,(
value1aaa,
value2
)
2016-09-02 20:42:30.779 lbCopy[4207:475091] strongMArr輸出:0x78f81680,(
value1aaa,
value2,
value3
)
2016-09-02 20:42:30.779 lbCopy[4207:475091] weakMArr輸/出:0x78f81680,(
value1aaa,
value2,
value3
)
//以上是輸出
上面代碼有點(diǎn)多柜裸,所做的操作是mArrOrigin(value1,value2)賦值給copy,strong,weak修飾的aCopyMArr,strongMArr,weakMArr。通過給原數(shù)組增加元素粱锐,修改原數(shù)組元素值疙挺,然后輸出mArrOrigin的引用計(jì)數(shù),和數(shù)組地址怜浅,查看變化铐然。
發(fā)現(xiàn)其中數(shù)組本身指向的內(nèi)存地址除了aCopyMArr重新開辟了一塊地址,strongMArr,weakMArr和mArrOrigin指針指向的地址是一樣的恶座。也就是說
容器可變變量中容器本身和非容器可變變量是一樣的搀暑,copy深拷貝,strongMArr,weakMArr和assign都是淺拷貝
另外我們發(fā)現(xiàn)被拷貝對(duì)象mArrOrigin中的數(shù)據(jù)引用計(jì)數(shù)居然不是1而是3跨琳。也就是說容器內(nèi)的數(shù)據(jù)拷貝都是進(jìn)行了淺拷貝自点。同時(shí)當(dāng)我們修改數(shù)組中的一個(gè)數(shù)據(jù)時(shí)strongMArr,weakMArr,aCopyMArr中的數(shù)據(jù)都改變了脉让,說明
容器可變變量中的數(shù)據(jù)在拷貝的時(shí)候都是淺拷貝
容器可變變量的拷貝結(jié)構(gòu)如下圖
2.2非容器不變變量
典型例子是NSString
我們還是以代碼引出結(jié)果
@property(copy,nonatomic)NSString*aCopyStr;
@property(strong,nonatomic)NSString*strongStr;
@property(weak,nonatomic)NSString*weakStr;
@property(assign,nonatomic)NSString*assignStr;
NSLog(@"\\n\\n\\n\\n------------------不可變量實(shí)驗(yàn)------------------------");
NSString*strOrigin = [[NSStringalloc]initWithUTF8String:"strOrigin0123456"];
self.aCopyStr= strOrigin;
self.strongStr= strOrigin;
self.weakStr= strOrigin;
NSLog(@"strOrigin輸出:%p,%@\\n", strOrigin,strOrigin);
NSLog(@"aCopyStr輸出:%p,%@\\n",_aCopyStr,_aCopyStr);
NSLog(@"strongStr輸出:%p,%@\\n",_strongStr,_strongStr);
NSLog(@"weakStr輸出:%p,%@\\n",_weakStr,_weakStr);
NSLog(@"------------------修改原值后------------------------");
strOrigin =@"aaa";
NSLog(@"strOrigin輸出:%p,%@\\n", strOrigin,strOrigin);
NSLog(@"aCopyStr輸出:%p,%@\\n",_aCopyStr,_aCopyStr);
NSLog(@"strongStr輸出:%p,%@\\n",_strongStr,_strongStr);
NSLog(@"weakStr輸出:%p,%@\\n",_weakStr,_weakStr);
NSLog(@"------------------結(jié)論------------------------");
NSLog(@"strOrigin值值為改變樟氢,但strOrigin和aCopyStr指針地址和指向都已經(jīng)改變,說明不可變類型值不可被修改侠鳄,重新初始化");
self.aCopyStr=nil;
self.strongStr=nil;
NSLog(@"strOrigin輸出:%p,%@\\n", strOrigin,strOrigin);
NSLog(@"aCopyStr輸出:%p,%@\\n",_aCopyStr,_aCopyStr);
NSLog(@"strongStr輸出:%p,%@\\n",_strongStr,_strongStr);
NSLog(@"weakStr輸出:%p,%@\\n",_weakStr,_weakStr);
NSLog(@"------------------結(jié)論------------------------");
NSLog(@"當(dāng)只有weakStr擁有C時(shí),值依舊會(huì)被釋放死宣,同非容器可變變量");
//以下是輸出
------------------不可變量實(shí)驗(yàn)------------------------
2016-09-02 21:08:44.053 lbCopy[4297:488549] strOrigin輸出:0x7a2550d0,strOrigin0123456
2016-09-02 21:08:44.053 lbCopy[4297:488549] aCopyStr輸出:0x7a2550d0,strOrigin0123456
2016-09-02 21:08:44.054 lbCopy[4297:488549] strongStr輸出:0x7a2550d0,strOrigin0123456
2016-09-02 21:08:44.054 lbCopy[4297:488549] weakStr輸出:0x7a2550d0,strOrigin0123456
2016-09-02 21:08:44.054 lbCopy[4297:488549] strOrigin值內(nèi)存引用計(jì)數(shù)3
2016-09-02 21:08:44.054 lbCopy[4297:488549] ------------------修改原值后------------------------
2016-09-02 21:08:44.054 lbCopy[4297:488549] strOrigin輸出:0x8c1f8,aaa
2016-09-02 21:08:44.054 lbCopy[4297:488549] aCopyStr輸出:0x7a2550d0,strOrigin0123456
2016-09-02 21:08:44.054 lbCopy[4297:488549] strongStr輸出:0x7a2550d0,strOrigin0123456
2016-09-02 21:08:44.055 lbCopy[4297:488549] weakStr輸出:0x7a2550d0,strOrigin0123456
2016-09-02 21:08:44.055 lbCopy[4297:488549] ------------------結(jié)論------------------------
2016-09-02 21:08:44.055 lbCopy[4297:488549] strOrigin值值為改變伟恶,但strOrigin和aCopyStr指針地址和指向都已經(jīng)改變,說明不可變類型值不可被修改毅该,重新初始化
2016-09-02 21:08:44.059 lbCopy[4297:488549] strOrigin輸出:0x8c1f8,aaa
2016-09-02 21:08:44.059 lbCopy[4297:488549] aCopyStr輸出:0x0,(null)
2016-09-02 21:08:44.060 lbCopy[4297:488549] strongStr輸出:0x0,(null)
2016-09-02 21:08:44.060 lbCopy[4297:488549] weakStr輸出:0x0,(null)
2016-09-02 21:08:44.060 lbCopy[4297:488549] ------------------結(jié)論------------------------
2016-09-02 21:08:44.061 lbCopy[4297:488549]當(dāng)只有weakStr擁有C時(shí)博秫,值依舊會(huì)被釋放潦牛,同非容器可變變量
//以上是輸出
此處我們將strOrigin拷貝給aCopyStr,strongStr挡育,weakStr巴碗,然后輸出他們的值地址,發(fā)現(xiàn)他們四個(gè)的值地址一樣即寒,且strOrigin值的引用計(jì)數(shù)為3橡淆。修改strOrigin和發(fā)現(xiàn)strOrigin值地址改變,其他三個(gè)值地址不變母赵,將aCopyStr逸爵,strongStr設(shè)為nil后,發(fā)現(xiàn)weakStr隨之nil凹嘲。
綜合上面現(xiàn)象NSString和NSMutableString(非容器可變變量)基本相同师倔,除了copy,NSString為淺拷貝周蹭,NSMutableString是深拷貝趋艘。那么為什么NSString的copy是淺拷貝呢,也就是說為什么aCopyStr不自己開辟一個(gè)獨(dú)立的內(nèi)存出來呢凶朗。答案很簡(jiǎn)單瓷胧,因?yàn)椴豢勺兞康闹挡粫?huì)改變,既然都不會(huì)改變俱尼,所以沒必要重新開辟一個(gè)內(nèi)存出來讓aCopyStr指向他抖单,直接指向原來值位置就可以了。示意圖如下
所以非容器不可變量除了copy其他特性同非容器可變變量遇八,copy是淺拷貝
2.3不可變?nèi)萜髯兞?/h3>
典型對(duì)象NSArray矛绘。該對(duì)象實(shí)驗(yàn)自行實(shí)驗(yàn)。但結(jié)論在這里給出刃永,其實(shí)不實(shí)驗(yàn)也可以大概知道概率
在不可變?nèi)萜髯兞恐谢醢萜鞅旧矶际菧\拷貝包括copy,同NSString斯够,容器里面的數(shù)據(jù)都是淺拷貝囚玫,同NSMutableArray。
3.總結(jié)
copy读规,strong抓督,weak,assign的區(qū)別束亏。
可變變量中铃在,copy是重新開辟一個(gè)內(nèi)存,strong,weak定铜,assgin后三者不開辟內(nèi)存阳液,只是指針指向原來保存值的內(nèi)存的位置,storng指向后會(huì)對(duì)該內(nèi)存引用計(jì)數(shù)+1揣炕,而weak帘皿,assgin不會(huì)。weak畸陡,assgin會(huì)在引用保存值的內(nèi)存引用計(jì)數(shù)為0的時(shí)候值為空鹰溜,并且weak會(huì)將內(nèi)存值設(shè)為nil,assign不會(huì)罩锐,assign在內(nèi)存沒有被重寫前依舊可以輸出奉狈,但一旦被重寫將出現(xiàn)奔潰
不可變變量中,因?yàn)橹当旧聿豢杀桓淖兩螅琧opy沒必要開辟出一塊內(nèi)存存放和原來內(nèi)存一模一樣的值仁期,所以內(nèi)存管理系統(tǒng)默認(rèn)都是淺拷貝。其他和可變變量一樣竭恬,如weak修飾的變量同樣會(huì)在內(nèi)存引用計(jì)數(shù)為0時(shí)變?yōu)閚il跛蛋。
容器本身遵守上面準(zhǔn)則,但容器內(nèi)部的每個(gè)值都是淺拷貝痊硕。
**綜上所述赊级,當(dāng)創(chuàng)建property構(gòu)造器創(chuàng)建變量value1的時(shí)候,使用copy岔绸,strong理逊,weak,assign根據(jù)具體使用情況來決定盒揉。value1 = value2晋被,如果你希望value1和value2的修改不會(huì)互相影響的就用用copy,反之用strong,weak,assign刚盈。如果你還希望原來值C(C是什么見示意圖1)為nil的時(shí)候羡洛,你的變量不為nil就用strong,反之用weak和assign。weak和assign保證了不強(qiáng)引用某一塊內(nèi)存藕漱,如delegate我們就用weak表示欲侮,就是為了防止循環(huán)引用的產(chǎn)生。
另外肋联,我們上面討論的是類變量威蕉,直接創(chuàng)建局部變量默認(rèn)是Strong修飾
**
補(bǔ)充:delegate為什么要用weak或者assign而不用strong
a創(chuàng)建對(duì)象b,b中有C類對(duì)象c,所以a對(duì)b有一個(gè)引用,b對(duì)c有一個(gè)引用橄仍,a.b引用計(jì)數(shù)分別為1忘伞,1。當(dāng)c.delegate = b的時(shí)候,實(shí)則是對(duì)b有了一個(gè)引用氓奈,如果此時(shí)c的delegate用strong修飾則會(huì)對(duì)b的值內(nèi)存引用計(jì)數(shù)+1,b引用計(jì)數(shù)為2鼎天。當(dāng)a的生命周期結(jié)束舀奶,隨之釋放對(duì)b的引用,b的引用計(jì)數(shù)變?yōu)?斋射,導(dǎo)致b不能釋放育勺,b不能釋放又導(dǎo)致b對(duì)c的引用不能釋放,c引用計(jì)數(shù)還是為1罗岖,這樣就造成了b和c一直留在了內(nèi)存中涧至。
而要解決這個(gè)問題就是使用weak或者assign修飾delegate,這樣雖然會(huì)有c仍然會(huì)對(duì)b有一個(gè)引用桑包,但是引用是弱引用南蓬,當(dāng)a生命周期結(jié)束的時(shí)候,b的引用計(jì)數(shù)變?yōu)?哑了,b釋放后隨之c的引用消失赘方,c引用計(jì)數(shù)變?yōu)?,釋放弱左。
不可變常量的特殊性
在2.2的討論中如果你
1.字符串改成小于10長(zhǎng)度的字符串
2.NSString*strOrigin = @"strOrigin0123456";
初始化NSString窄陡,你都會(huì)發(fā)現(xiàn)strOrigin值內(nèi)存引用計(jì)數(shù)將發(fā)生異常,通常表現(xiàn)為引用計(jì)數(shù)特別大拆火,具體可以看下iOS中NSString的特別之處這篇文章
項(xiàng)目地址https://github.com/ai966669/copy
交流qq:578172874
錯(cuò)誤之處希望能幫忙提出來跳夭,O(∩_∩)O謝謝了