前天面試問到NSTimer的循環引用,面試者說了一個他從網上找的方法:
給
NSTimer
建立一個類方法,内部設定
target
為
NSTimer
類,然後通過
block
回調供外部使用。
當時聽到這個感覺有個問題,目前控制器确實會正常釋放,那怎麼確定定時器也正常釋放了呢?他當時說沒有考慮過這個問題。我想了一下自己使用定時器的時候,觀察的是定時器方法,通過調用
invalidate
方法,保證計時器方法不會再調用,就o了。那這樣真的可以保證定時器釋放嗎?檢視下API說明如下:
Timers work in conjunction with run loops. Run loops maintain strong references to their timers, so you don’t have to maintain your own strong reference to a timer after you have added it to a run loop.
這裡說
Run loops
會強引用
Timers
,是以就算我們外部沒有強引用
Timers
,也能夠正常使用它的計時功能。
Once scheduled on a run loop, the timer fires at the specified interval until it is invalidated. A nonrepeating timer invalidates itself immediately after it fires. However, for a repeating timer, you must invalidate the timer object yourself by calling its invalidate method. Calling this method requests the removal of the timer from the current run loop; as a result, you should always call the invalidate method from the same thread on which the timer was installed. Invalidating the timer immediately disables it so that it no longer affects the run loop. The run loop then removes the timer (and the strong reference it had to the timer), either just before the invalidate method returns or at some later point. Once invalidated, timer objects cannot be reused.
這裡說明了對于一個重複計時的定時器,通過調用
invalidate
方法,定時器會終止并從
Run loops
中移除。也就是說我用完計時器然後調用
invalidate
方法就不會出現記憶體洩露了。
其實上面那個面試者說的方法,網上也有,最終也是通過調用
invalidate
解決的。
通過上面的分析,正确使用
Timer
就不會造成記憶體洩露了,那麼該如何證明呢。一般來說,如果對象釋放,一定會走
dealloc
方法。隻要重寫
dealloc
方法就行了。但是這個類是系統類,我們沒有辦法直接在源檔案中寫,那該怎麼寫呢?
1. 子類化并重寫
dealloc
方法。
Subclassing Notes
Do not subclass NSTimer.
API中說不能夠子類化,是以排除此方案。
2. 通過
category
實作
dealloc
方法。使用此方法,代碼運作的時候會崩潰,應該是一直調用導緻的卡死。
3. 通過
instruments
檢查對象記憶體的開辟量。打開
instruments
并選擇
Allocations
。然後在下部的搜尋框中輸入
timer
,就可以看到計時器對象目前的記憶體暫用量了。