舉個簡單的例子:
對象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與消息轉發機制