前言
這篇文章僅僅回答weakSelf少辣、stongSelf是如何做到避免循環(huán)引用也延長執(zhí)行生命周期的。
這個小技巧可能都被iOS工程師們用到滾瓜熟爛了笤成,但同時也很可能有人還不知道原理的评架,所以小智就在這簡單介紹一下!
避免循環(huán)引用炕泳?
全世界都知道block會自動強引用里面調用的實例變量纵诞,SO,一旦block里面所直接引用了self就會引發(fā)循環(huán)引用培遵,為啥呢浙芙?
如上圖所示是一個直接強引用的示例圖。OK籽腕,假設這時self想要釋放自己茁裙,它的引用計數(shù)器必須清零,然后執(zhí)行dealloc去釋放掉它持有的屬性與實例變量节仿。
只是是不是看出點端倪來了晤锥。對了block是在dealloc的過程中執(zhí)行的,在ARC環(huán)境下把這些代碼都隱藏自動執(zhí)行了廊宪。SO矾瘾,因為block的強引用self,那么self的計數(shù)器就不會清零箭启,就不會執(zhí)行dealloc壕翩,不會執(zhí)行dealloc,那么block的釋放操作也不會執(zhí)行傅寡,就形成了循環(huán)引用放妈,造成self和block都不會被釋放掉,內存泄漏荐操。
那么引用引用了weakSelf呢芜抒?哈哈,如下圖所示:
我們繼續(xù)從引入計數(shù)來分析這個問題托启。block引用了weakSelf宅倒,因為是weakSelf所以self的引用計數(shù)器完全不受block的影響。所以self在執(zhí)行dealloc是愛咋地就咋地屯耸,只要count清零拐迁,就立即執(zhí)行蹭劈,還順便釋放掉block,所以weakSelf是能讓實現(xiàn)避免循環(huán)引用的問題线召。
延長執(zhí)行生命周期铺韧?
好像有weakSelf就能解決block的所有問題,這延長執(zhí)行生命周期有是什么鬼缓淹?
好的哈打,我們又來假設一種新的情況,假如你的block是個網絡請求回調割卖,而且這個回調是在非主線程異步執(zhí)行前酿,那么如果這時的self的count清零了绽慈,block中的回調都還未執(zhí)行完就被清零了傻咖,這有時還是會影響業(yè)務邏輯的系冗,要解決這個問題就需要引用strongSelf了,如下圖所示:
細心的大家會發(fā)現(xiàn)stringSelf變藍了丙挽,為什么不是變黃呢?那時因為紅色代表block外部定義的屬性變量匀借,而藍色表示是block中自己定義的局部變量颜阐。來到這里只要理清兩個概念,即可解開這個謎題吓肋,
- 一個指針對另外一個指針賦值,被賦值的指針實際上就是得到指向對象的地址
- 方法函數(shù)中的局部變量是存儲在棧內存區(qū)的是鬼,所以一旦方法函數(shù)執(zhí)行完,那么局部變量就會被釋放掉均蜜。
根據以上兩點得出上圖的簡略圖:
首先block只是在block只引用了weakSelf,所以不會引起循環(huán)引用。其次囤耳,每當block在執(zhí)行的時候篙顺,因為它的局部變量間接強引用self,所以self的count不會清零而執(zhí)行dealloc充择,確保了block能執(zhí)行完成,一旦block執(zhí)行完成椎麦,self又具備執(zhí)行dealloc的權利,那么就能安全釋放铃剔。
總結:
根據上文的原理闡述撒桨,發(fā)現(xiàn)通過weakSelf與strongSelf搭配使用查刻,能決定一個block是否需要延長生命周期確保執(zhí)行完畢。