當前位置:成語大全網 - 新華字典 - OC梳理循環引用及解決

OC梳理循環引用及解決

循環引用是iOS開發中經常遇到的問題,它指的是兩個或多個對象通過相互之間的強引用,形成了壹個保留環,即使已經沒有外部對象持有,也無法對其進行釋放操作,也無法釋放其占用的內存空間(引用計數器始終大於0)。

舉個簡單的例子:

對象A持有對象B,對象B持有對象C,對象C持有對象A,這時候它們之間就形成了壹個引用環:

這時候如果有壹個對象D,引用了對象A,那麽由於ABC之間的循環引用,它們的引用計數器如下:

那麽即使D釋放了對象A,A、B、C的引用計數器仍然都是1,它們都不會被釋放回收。

由於循環引用的存在,使得產生循環引用的對象始終占有內存空間,過多的循環引用會導致程序的內存占用不斷升高,最終導致程序Creach。

用weak而不是strong就能解決這個問題了:

Block的循環引用,主要是發生在ViewController中持有了block,比如:

同時在對callbackBlock進行賦值的時候又調用了ViewController的方法,比如:

就會發生循環引用,因為:ViewController->強引用了callback->強引用了ViewController,解決方法也很簡單:

那是不是所有的block都會發生循環引用呢?其實不然,比如UIView的類方法Block動畫,NSArray等的 類的遍歷方法,都不會發生循環引用,因為當前控制器壹般不會強引用壹個類。

NSTimer是壹種很容易忽略的循環引用的情況。

因為timer會強引用self,而self又持有了timer,這就造成了循環引用。

那麽能不能像Block那樣用壹個weak指針解決呢?比如

但是其實並沒有用,因為不管是weakSelf還是strongSelf,最終在NSTimer內部都會重新生成壹個新的指針指向self,這是壹個強引用的指針,結果就會導致循環引用。

如何解決呢?用NSProxy就是壹個狠簡便的方法

NSProxy本身是壹個抽象類,它遵循NSObject協議,提供了消息轉發的通用接口。NSProxy通常用來實現消息轉發機制和惰性初始化資源。

使用NSProxy,妳需要寫壹個子類繼承它,然後需要實現init以及消息轉發的相關方法:

創建NSTimer時,使用如下方法:

原理如下:

把虛線處變成了弱引用。於是,Controller就可以被釋放掉,我們在Controller的dealloc中調用invalidate,就斷掉了Runloop對Timer的引用,於是整個三個淡藍色的就都被釋放掉了。

參考文章: NSProxy與消息轉發機制