引用計(jì)數(shù)基本概念
當(dāng)創(chuàng)建一個(gè)新對(duì)象的時(shí)候嫉嘀,引用計(jì)數(shù)加1炼邀,當(dāng)某個(gè)指針不再指向這個(gè)對(duì)象時(shí),引用計(jì)數(shù)減1剪侮,當(dāng)對(duì)象的引用計(jì)數(shù)為0時(shí)拭宁,系統(tǒng)自動(dòng)將對(duì)象銷毀,回收內(nèi)存瓣俯。
引用《Pro Multithreading and Memory Management for iOS and OS X》中的圖片
我們?yōu)槭裁葱枰糜?jì)數(shù)
ARC模式下杰标,在同一個(gè)函數(shù)內(nèi),我們通常不需要手動(dòng)處理引用計(jì)數(shù)彩匕,此時(shí)的使用場(chǎng)景比較簡(jiǎn)單腔剂。引用計(jì)數(shù)真正發(fā)揮作用的場(chǎng)景在面向?qū)ο蟮某绦蛟O(shè)計(jì)架構(gòu)中,用于對(duì)象之間的傳遞和共享數(shù)據(jù)驼仪。
例如:對(duì)象A生成對(duì)象M掸犬,調(diào)用對(duì)象B的一個(gè)方法將M作為參數(shù)傳遞。根據(jù)(誰(shuí)申請(qǐng)誰(shuí)釋放)原則绪爸,應(yīng)該由A在B不需要M的時(shí)候來(lái)銷毀它湾碎。
那么問(wèn)題來(lái)了,B何時(shí)才不需要M是不確定的奠货。
Method 1:非常暴力的在A調(diào)用完對(duì)象B之后立刻銷毀對(duì)象M介褥,那么對(duì)象B就很懵逼的需要將參數(shù)另外復(fù)制一份M2,自己來(lái)管理對(duì)象M2的生命周期递惋。
這樣有一個(gè)很大的問(wèn)題:大量的內(nèi)存申請(qǐng)柔滔,復(fù)制,釋放操作丹墨,實(shí)在太影響性能廊遍。
Method 2:使用引用計(jì)數(shù),哪些對(duì)象需要長(zhǎng)時(shí)間使用M贩挣,就把它的引用計(jì)數(shù)加1喉前,用完之后再把引用計(jì)數(shù)減1,所有對(duì)象都遵循這個(gè)原則王财,生命周期管理的重任就交給引用計(jì)數(shù)了卵迂。
不要向已經(jīng)釋放的對(duì)象發(fā)送消息
手動(dòng)release一個(gè)對(duì)象,打印其引用計(jì)數(shù)為什么不是0绒净?
理論上說(shuō)见咒,一個(gè)被release的對(duì)象的引用計(jì)數(shù)值是不確定的,而且如果該對(duì)象所占有的內(nèi)存已經(jīng)被復(fù)用挂疆,那么打印其引用計(jì)數(shù)值程序可能會(huì)異常崩潰改览。
當(dāng)系統(tǒng)確定一個(gè)對(duì)象要被release后下翎,就沒(méi)有必要對(duì)它進(jìn)行引用計(jì)數(shù)減1了。因?yàn)榭隙〞?huì)被回收宝当,回收后视事,它所擁有的內(nèi)存區(qū)域,包括retainCount值都變得沒(méi)有意義庆揩。
不進(jìn)行減1可以減少內(nèi)存操作俐东,加速對(duì)象回收。
Perfect But 問(wèn)題又來(lái)了
reference cycles 循環(huán)引用
這也是ARC的一個(gè)痛點(diǎn)订晌,對(duì)象A與對(duì)象B如果互相持有虏辫,就會(huì)造成循環(huán)引用,即使沒(méi)有任何指針訪問(wèn)它們锈拨,也不會(huì)被釋放砌庄。這樣的情況也多發(fā)生在多個(gè)對(duì)象互相持有,block的使用 NSTimer等奕枢。
Method 1:明確會(huì)造成循環(huán)引用的位置鹤耍,主動(dòng)斷開其中一環(huán)。
Method 2:使用weak reference(弱引用)
持有對(duì)象验辞,但不增加引用計(jì)數(shù)稿黄,避免循環(huán)應(yīng)用的產(chǎn)生。比如delegate通常是弱引用的跌造。
關(guān)于block中的循環(huán)引用
在block中的循環(huán)引用一般會(huì)被編譯器所提醒杆怕,但并不是使用到self才會(huì)造成循環(huán)引用,只要用到self所擁有的東西都會(huì)壳贪。需要使用其它指針來(lái)避免block對(duì)自身強(qiáng)引用陵珍,如下:
__weak typeof(self) weakSelf = self;
self.blkA = ^{
__strong typeof(weakSelf) strongSelf = weakSelf;//加一下強(qiáng)引用,避免weakSelf被釋放掉
NSLog(@"%@", strongSelf->_xxView); //不會(huì)導(dǎo)致循環(huán)引用.
};
這是針對(duì)ARC的方式违施,MRC下要用__block
通常情況下互纯,GCD 中的block并不會(huì)出現(xiàn)針對(duì)self循環(huán)引用的情況,因?yàn)閟elf并沒(méi)有對(duì)GCD中的block進(jìn)行持有磕蒲。
參考資料
1.《iOS 開發(fā)進(jìn)階》 唐巧
2.iOS中block的循環(huán)引用問(wèn)題 - 簡(jiǎn)書