NSTimer注意點(diǎn)及循環(huán)引用

NSTimer

  1. 作用:文檔又講:在固定的時(shí)間間隔被觸發(fā),給指定目標(biāo)發(fā)送消息。
  2. NSTimer使用必須注意點(diǎn)?
    1. 要想timer能夠運(yùn)行起來,必須將timer實(shí)例 添加到 指定線程的Runloop下某個(gè)model下. 上面一句話蘊(yùn)含幾點(diǎn):
      1.1. 必須存在線程
      1.2. 指定線程的Runloop必須啟動
      1.3. 必須將timer添加到Runloop的某個(gè)model下(即:timer作為Model的item)
    1. Runloop 與 timer 關(guān)系? 文檔中是這樣寫的:

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.
上面文檔提出幾個(gè)注意點(diǎn):

  1. timer必須運(yùn)行在runloop中,不重復(fù)的timer,觸發(fā)后系統(tǒng)立即使其自身無效. 重復(fù)的timer,必須調(diào)用invalidate方法才能使timer無效,且調(diào)用invalidate方法后會請求從runloop刪除timer.
  2. 使用timer與廢棄timer必須在同一個(gè)線程中.
  3. Runloop會在invalidate方法返回之前或之后的某個(gè)時(shí)間點(diǎn)移除timer(即:移除runloop對timer的強(qiáng)引用)
  4. 一旦失效,就不能重用計(jì)時(shí)器對象。
    1. 根據(jù)2中文檔所知,runloop會對timer有強(qiáng)引用.
    1. timer會對目標(biāo)對象target進(jìn)行強(qiáng)引用
  • 5.invalidate方法作用? 文檔說明:

Stops the timer from ever firing again and requests its removal from its run loop.
//即:停止timer再次被觸發(fā),且請求從runloop中移除

NSTimer如何解決循環(huán)引用?

  1. 首選講NSTimer使用時(shí)產(chǎn)生循環(huán)引用的原因?
    // 實(shí)線:強(qiáng)引用,虛線:弱引用


    屏幕快照 2019-09-17 下午6.10.05.png
  • 可以看出無論self對timer是強(qiáng)/弱引用,timer始終強(qiáng)持有self實(shí)例.當(dāng)self強(qiáng)引用timer時(shí),self與timer相互引用,肯定造成循環(huán).當(dāng)self弱引用timer時(shí),timer一旦被觸發(fā),則timer一定被添加到runloop中,這時(shí)runloop強(qiáng)持有timer,timer強(qiáng)持有self,若self是NSObject,UIView,UIViewController的實(shí)例,就要求runloop退出(model的item為空)或被釋放(線程被銷毀),但runloop對應(yīng)線程是主線程時(shí),就造成self無法被釋放.
  1. 解決方案?
  • 直接方法:
    2.1.1. 使用iOS10之后新出的block回調(diào)方式.
    2.1.2.攔截pop方法,廢棄timer.不同開發(fā)人有不同的方案.我這里是通過自定義navigation,重寫pop方法,下沉給nav.toViewController, self實(shí)現(xiàn)相應(yīng)方法,調(diào)用timer的invalidate
    2.1.3. 在viewDidDisappear里 調(diào)用timer的invalidate.(self is UIViewController)
  • 類方法方案:(強(qiáng)力推薦,因?yàn)闊o需外部調(diào)用timer的invalidate,避免遺忘)

就是通過將timer的target設(shè)置為一個(gè)類對象.雖然相互持有關(guān)系沒有被打破,可是因?yàn)轭悓ο螅╟lass object)無需回收,所以不用擔(dān)心。

  • 消息轉(zhuǎn)發(fā)方案:

就是通過將timer的target設(shè)置為一個(gè)NSProxy的實(shí)例,自定義繼承NSProxy類,實(shí)現(xiàn)消息轉(zhuǎn)發(fā)方法. 就是說:timer調(diào)用target(proxy實(shí)例)的selector,利用消息轉(zhuǎn)發(fā)原理,回調(diào)self的selector

  • RunTime方案:

就是隨意創(chuàng)建一個(gè)object作為timer的selector,給object添加實(shí)例方法,添加的實(shí)例方法就是timer觸發(fā)的消息方法.

  • Block方案:

即給NSTimer添加分類,添加類方法獲取timer實(shí)例,將timer的target設(shè)置為NSTimer類對象(簡介利用了類方法方案),打破timer對self的強(qiáng)持有關(guān)系.

具體實(shí)現(xiàn)代碼https://github.com/zhbgitHub/NSTimerUse
代碼中注釋有應(yīng)該的注意點(diǎn)及timer占用資源的釋放說明.

  • 使用GCD定時(shí)器取代NSTimer(較簡單直接貼代碼)
@interface xxx ()
@property (nonatomic, strong) dispatch_source_t timer;
@end

- (void)startTimer
{
   dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    self.timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, globalQueue);
    dispatch_source_set_timer(_timer, dispatch_time(DISPATCH_TIME_NOW, 0), 2.0*NSEC_PER_SEC, 0);
    dispatch_source_set_event_handler(_timer, ^{
        dispatch_async(dispatch_get_main_queue(), ^{
            NSLog(@"執(zhí)行了");
        });
    });
    //開啟計(jì)時(shí)器
    dispatch_resume(_timer);
}

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

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

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