【Swift】Timer定時器到底准不准確?


  在開發過程中,Timer可以說是比較常見的了,用來做一些定時性的操作。可實際過成功,Timer的時間真的准嗎?下面寫幾個代碼來做驗證。

  1、Timer

timer = Timer.scheduledTimer(timeInterval: 1.0, target:self, selector: #selector(timerTest), userInfo: nil, repeats: true)

@objc func timerTest() {
        print("timer info - \(Date.init())")
 }

  運行結果:

timer info - 2020-10-28 05:02:33 +0000
timer info - 2020-10-28 05:02:34 +0000
timer info - 2020-10-28 05:02:35 +0000
timer info - 2020-10-28 05:02:36 +0000

  看結果還是比較准備的,不妨加大量繼續測試。在輸入時加一些耗時操作。

    @objc func timerTest() {
        var count = 0
        for index in 0..<100000 {
            count += 1
        }
        print("timer info - \(Date.init())")
    }

  再看運行結果:

timer info - 2020-10-28 05:04:20 +0000
timer info - 2020-10-28 05:04:21 +0000
timer info - 2020-10-28 05:04:22 +0000
timer info - 2020-10-28 05:04:23 +0000
timer info - 2020-10-28 05:04:24 +0000
timer info - 2020-10-28 05:04:25 +0000
timer info - 2020-10-28 05:04:26 +0000

  還可以嘛!結果依然看起來挺對的,那就繼續加大工作量。再測試:

@objc func timerTest() {
        var count = 0
        for index in 0..<10000000 {
            count += 1
        }
        print("timer info - \(Date.init())")
    }

  看運行結果:

timer info - 2020-10-28 05:05:19 +0000
timer info - 2020-10-28 05:05:23 +0000
timer info - 2020-10-28 05:05:27 +0000
timer info - 2020-10-28 05:05:31 +0000

  這時候結果就明顯了,我要求的定時是1秒鍾,可間隔出現了竟然4秒了。這跟我要求的就相差很大了。可這是怎么出現的呢?

  原因分析:

  定時器被添加在主線程中,由於定時器在一個RunLoop中被檢測一次,所以如果在這一次的RunLoop中做了耗時的操作,當前RunLoop持續的時間超過了定時器的間隔時間,那么下一次定時就被延后了。

  解決辦法:

  1、在子線程中創建timer,在主線程進行定時任務的操作
  2、在子線程中創建timer,在子線程中進行定時任務的操作,需要UI操作時切換回主線程進行操作  

Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { (timer) in
            print("timer info - \(Date.init())")
        }

  2、RunLoop模式的影響

  為了驗證,我們在當前頁面上添加一個tableview,在定時器運行時,我們對tableview進行滑動操作,可以發現,定時器並不會觸發下一次的定時任務。

  原因分析:

  主線程的RunLoop有兩種預設的模式,RunLoopDefaultMode和TrackingRunLoopMode。
  當定時器被添加到主線程中且無指定模式時,會被默認添加到DefaultMode中,一般情況下定時器會正常觸發定時任務。但是當用戶進行UI交互操作時(比如滑動tableview),主線程會切換到TrackingRunLoopMode,在此模式下定時器並不會被觸發。

  解決方法:

  添加定時器到主線程的CommonMode中或者子線程中

        timer = Timer.scheduledTimer(timeInterval: 1.0, target:self, selector: #selector(timerTest), userInfo: nil, repeats: true)
//
        RunLoop.main.add(timer, forMode: .common)

  總結

  從結果看,Timer在其使用場景下足夠准了,對於“不准”更多是集中在對其錯誤的使用方式上,只要我們足夠深入了解,正確地使用,就能讓它“准”。

  實際上,蘋果也不推薦使用太高精度的定時器,對於Timer,精度在50-100ms都是正常的,如果我們需要足夠高精度地進行計時,比如統計APP啟動時間、一段任務代碼的運行時間等等,Timer不是一個好的選擇,mach_absolute_time()或者可以幫到你,蘋果開發工具也帶有更專業的API或者插件提供給開發者。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM