線程中的Timer

突然有個疑問: 在一個子線程中啟動一個timer,但是不添加到Runloop中,調(diào)用timer.fire(),這時候timer 會運行嗎?

實踐出真知 ??

   var  times = 1;
        let thread = Thread { 
            let   timer = Timer(timeInterval: 1, repeats: true, block: { (timer) in
                print("repeating \(Date.init()) times = \(times)")
                if(times < 20){
                    times += 1
                }else{
                    timer.invalidate()
                }
                
            })
            timer.fire()
            //RunLoop.current.add(timer, forMode: .defaultRunLoopMode)
            print(timer.fireDate)
            RunLoop.current.run(mode: .defaultRunLoopMode, before:Date(timeIntervalSinceNow: 10))// runloop運行后 在10s 后退出
             //RunLoop.current.run(until: Date.distantFuture)
            print(timer.fireDate)
        }
        
        print("1 \(thread.isExecuting)")
        thread.start()
        print("2 \(thread.isExecuting)")
        let disTime = DispatchTime.now() + DispatchTimeInterval.seconds(4)
        DispatchQueue.global().asyncAfter(deadline:disTime) {
            print("3 \(thread.isExecuting)")
            print(thread)
            print(Thread.current)
        }

輸出結(jié)果是:


1 false
2 false
repeating 2017-03-26 02:38:35 +0000 times = 1
2017-03-26 02:38:36 +0000
2017-03-26 02:38:36 +0000
3 false
<NSThread: 0x60000026f740>{number = 3, name = (null)}
<NSThread: 0x600000271b00>{number = 4, name = (null)}

在沒有將timer add 到Runloop 中&& runloop 停止之前, timer 僅僅觸發(fā)了一次執(zhí)行操作。

WHY ?

到底這個timer 在線程中一直執(zhí)行沒有呢?很顯然,他就執(zhí)行一次(這與RunLoop 有何關(guān)系?)
那是不是Timer 執(zhí)行完就被釋放了呢,我們再看看3s 后 這個timer 是否還有效,times < 2, 添加3s 后檢查timer.isvalide

  var  times = 1;
        let thread = Thread { 
            let   timer = Timer(timeInterval: 1, repeats: true, block: { (timer) in
                print("repeating \(Date.init()) times = \(times)")
                if(times < 2){
                    times += 1
                }else{
                    timer.invalidate()
                }
                
            })
            timer.fire()
            //RunLoop.current.add(timer, forMode: .defaultRunLoopMode)
            print(timer.fireDate)
            RunLoop.current.run(mode: .defaultRunLoopMode, before:Date(timeIntervalSinceNow: 10))// runloop運行后 在10s 后退出
             //RunLoop.current.run(until: Date.distantFuture)
            print(timer.fireDate)
            DispatchQueue.global().asyncAfter(deadline: DispatchTime.now() + DispatchTimeInterval.seconds(3), execute: {
                print("after 3s  timer is running \(timer.isValid )")
            })
        }
        
        print("1 \(thread.isExecuting)")
        thread.start()
        print("2 \(thread.isExecuting)")
        let disTime = DispatchTime.now() + DispatchTimeInterval.seconds(4)
        DispatchQueue.global().asyncAfter(deadline:disTime) {
            print("3 \(thread.isExecuting)")
            print(thread)
            print(Thread.current)
            
        }
        
        

在看輸出:


1 false
2 true
repeating 2017-03-26 03:01:41 +0000 times = 1
2017-03-26 03:01:42 +0000
2017-03-26 03:01:42 +0000
after 3s  timer is running true
3 false
<NSThread: 0x60000007f100>{number = 3, name = (null)}
<NSThread: 0x600000261900>{number = 4, name = (null)}

我認(rèn)為 timer 就是一個線程,沒有將其加入到Runloop ,該timer執(zhí)行完他的代碼就退出了。

可是線程要Runloop 干嘛呢?不是沒有runLoop 線程也可以執(zhí)行嗎?確實是。
RunLoop 存在的意義在于有如果我們需要隨時處理事件并保持線程不退出
RunLoop 存在的意義在于有如果我們需要隨時處理事件并保持線程不退出
RunLoop 存在的意義在于有如果我們需要隨時處理事件并保持線程不退出

CFRunLoopTimerRef 是基于時間的觸發(fā)器,它和 NSTimer 是toll-free bridged 的,可以混用。其包含一個時間長度和一個回調(diào)(函數(shù)指針)。當(dāng)其加入到 RunLoop 時,RunLoop會注冊對應(yīng)的時間點,當(dāng)時間點到時,RunLoop會被喚醒以執(zhí)行那個回調(diào)。

根據(jù)這個說法那就不難理解,如果不添加到Runloop ,Runloop 沒有可接收的消息源,所在線程執(zhí)行完后就退出。

一般滑動列表的時候我們還有一個timer 在運行,發(fā)現(xiàn)Timer 的回調(diào)不執(zhí)行。原因有二

  1. 滑動列表是在TrackingMode,Timer 在defaultMode
  2. 同一時刻Runloop只對應(yīng)一個Mode

從timer 的mode 切換到 trackingMode,Timer 的回調(diào)不執(zhí)行,但是再次執(zhí)行的時候會順延至指定的間隔的整數(shù)倍(比如我們4:10 開啟,每隔1m 調(diào)用一次,在4:12 切換到TrackingMode 4 m 后再切回來,那下次啟動大概就是4:17 左右開始回調(diào)執(zhí)行)

參考

Runloop的add 方法

func add(_ timer: Timer, forMode mode: RunLoopMode)
Description
Registers a given timer with a given input mode.
You can add a timer to multiple input modes. While running in the designated mode, the receiver causes the timer to fire on or after its scheduled fire date. Upon firing, the timer invokes its associated handler routine, which is a selector on a designated object.
The receiver retains aTimer. To remove a timer from all run loop modes on which it is installed, send an invalidate() message to the timer.

深入理解RunLoop

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容