iOS 關(guān)于控制器未被釋放的問(wèn)題

前言:今天同事突然跟我說(shuō),工程里有很多控制器并未銷毀,關(guān)于這個(gè)問(wèn)題我一直沒(méi)太在意,就趁著有時(shí)間就查了查資料然后進(jìn)行修改和測(cè)試,得到了以下結(jié)論!
如何查看控制器是否銷毀,我們?cè)?ARC 模式下可以重寫 dealloc 方法,可以打個(gè)斷點(diǎn)或者 NSLog 一下,如果未執(zhí)行就說(shuō)明當(dāng)前控制器未被銷毀,或許如果你想查看當(dāng)前控制器的引用計(jì)數(shù)可以在視圖將要消失的方法中打個(gè)斷點(diǎn),在控制臺(tái)執(zhí)行 po self.retainCount 就會(huì)看到當(dāng)前控制器被引用的計(jì)數(shù)了,當(dāng)然在這里打印實(shí)際上是不準(zhǔn)的?。?!
控制器在被pop后移出棧后會(huì)被釋放,但有些時(shí)候會(huì)發(fā)現(xiàn)控制器出棧的時(shí)候不會(huì)調(diào)用dealloc方法,歸根結(jié)底,是因?yàn)楫?dāng)前控制器被某個(gè)對(duì)象強(qiáng)引用了,控制器的引用計(jì)數(shù)不為0,系統(tǒng)無(wú)法幫你釋放這部分內(nèi)存。
注:重寫 deallocd方法不需要手動(dòng)調(diào)用父類的dealloc,手寫[super dealloc]方法會(huì)報(bào)錯(cuò),事實(shí)上系統(tǒng)會(huì)自動(dòng)幫你調(diào)用父類的dealloc方法,不需要你實(shí)現(xiàn)??梢酝ㄟ^(guò)在dealloc方法中打印log查看控制器是否被釋放。

控制器未被銷毀,基本上就是三種原因:

  • 控制器中block的循環(huán)引用
    block會(huì)把它里面的所有對(duì)象強(qiáng)引用(在ARC下)/PS:MRC下會(huì)retain加1/,包括當(dāng)前控制器self,因此有可能會(huì)出現(xiàn)循環(huán)引用的問(wèn)題。
    即一個(gè)對(duì)象有一個(gè)Block屬性,然而這個(gè)Block屬性中又引用了對(duì)象的其他成員變量,那么就會(huì)對(duì)這個(gè)變量本身產(chǎn)生強(qiáng)應(yīng)用,那么這個(gè)對(duì)象本身和他自己的Block屬性就形成了循環(huán)引用。在ARC下需要修改成這樣:(/也就是生成一個(gè)對(duì)自身對(duì)象的弱引用/)
    __weak typeof(self) weakSelf = self;
    即:保險(xiǎn)起見(jiàn)block中所有的涉及到self的全給替換成weakSelf

以下是我工程中出現(xiàn)的問(wèn)題,同仁們也可以在自己的項(xiàng)目中從以下幾點(diǎn)出發(fā)查看
1.在 block 內(nèi)部無(wú)論是屬性或者是實(shí)例變量都會(huì)在 block 內(nèi)部被強(qiáng)引用,所以在檢查時(shí)要注意內(nèi)部的屬性或者實(shí)例變量是否進(jìn)行了弱引用,我目前的解決辦法是將實(shí)例變量改為了屬性!
2.在系統(tǒng)編譯時(shí),雖然我們未執(zhí)行 block 的內(nèi)部代碼,但是編譯器在編譯時(shí)都會(huì)默認(rèn)讀取的,所以在項(xiàng)目中你認(rèn)為很多未執(zhí)行或?qū)懺?return 后面你認(rèn)為不會(huì)執(zhí)行的代碼系統(tǒng)都會(huì)編譯的,盡量做到不用的代碼刪除掉!
3.如果項(xiàng)目中我們使用了自定義的視圖(例如 cell),如果在自定義的視圖中引用了某個(gè)控制器,我們要將控制器進(jìn)行一次弱引用,避免出現(xiàn)循環(huán)引用的問(wèn)題!

  • 控制器中的代理不是weak屬性

例如@property (nonatomic, weak) id<CustmViewDelegate> delegate;代理要使用弱引用,因?yàn)樽远x控件是加載在視圖控制器中的,視圖控制器view對(duì)自定義控件是強(qiáng)引用,
如果代理屬性設(shè)置為strong,則意味著delegate對(duì)視圖控制器也進(jìn)行了強(qiáng)引用,會(huì)造成循環(huán)引用。導(dǎo)致控制器無(wú)法被釋放,最終導(dǎo)致內(nèi)存泄漏。

  • 控制器中NSTimer沒(méi)有被銷毀

當(dāng)控制器中存在NSTimer時(shí),就需要注意,因?yàn)楫?dāng)[NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(updateTime:) userInfo:nil repeats:YES];時(shí),這個(gè)/target:self/ 就增加了VC的RetarnCountr, 如果你不將這個(gè)timer invalidate,就別想調(diào)用dealloc。需要在viewWillDisappear之前需要把控制器用到的NSTimer銷毀。
[timer invalidate]; // 銷毀timer
timer = nil; // 置nil

這篇文章我主要是說(shuō)一下在項(xiàng)目中出現(xiàn)的問(wèn)題,主要還是 block 內(nèi)部未對(duì)屬性進(jìn)行弱引用,文章中主要參考了[https://segmentfault.com/a/1190000003858306] 這篇文章,并且 copy 了許多并結(jié)合我在項(xiàng)目中出現(xiàn)的問(wèn)題,本人才疏學(xué)淺,文章中有不當(dāng)?shù)牡胤竭€請(qǐng)各位同仁指正,并一起交流,十分感謝!

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

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

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