iOS中的3種定時器

滴水微瀾發表於2023-05-10
在iOS中有3種常見的定時器,它們會根據不同的場景進行選擇使用。
1.DispatchSourceTimer: 基於GCD實現。
2.CADisplayLink:基於螢幕重新整理實現。
3.Timer:基於RunLoop實現。

DispatchSourceTimer定時器
DispatchSourceTimer定時器可以透過DispatchSource.makeTimerSource(queue: DispatchQueue.main)方法來建立,並且
使用GCD建立了一個DispatchSource型別的定時器,並使用全域性佇列來執行它。透過schedule(deadline: .now(), repeating: .seconds(1))方法指定定時器的初始延遲和重複時間,然後設定了一個事件處理程式來定義定時器要執行的操作。
最後timer.resume()啟動定時器。
要停止定時器,可以呼叫timer.cancel()方法。
優點為:Dispatch定時器非常輕量級,基於GCD的實現,可以利用GCD的優勢來進行任務排程,效能高。
var timer: DispatchSourceTimer?
func startCountdown() {
    //一般倒數計時是操作UI,使用主佇列
    timer = DispatchSource.makeTimerSource(queue: DispatchQueue.main)
    // //耗時操作放在全域性佇列,子執行緒處理
    // timer = DispatchSource.makeTimerSource(queue: DispatchQueue.global())
    timer.schedule(deadline: .now(), repeating: .seconds(1))
    timer.setEventHandler {
        // 定時器執行的操作
    }
    timer.resume()
}

deinit {
    timer.cancel()
    timer = nil
}
CADisplayLink定時器
CADisplayLink定時器可以透過CADisplayLink(target: self, selector: #selector(update))方法建立,並且透過displayLink.add(to: .main, forMode: .common)方法將定時器新增到主執行迴圈中,並指定了執行模式。
然後定義update方法,該方法將在每個定時器週期中執行。
在物件銷燬前停止定時器,可以呼叫displayLink.invalidate()方法。
CADisplayLink物件一旦建立就會執行,比較適合監控主執行緒UI卡頓,用做倒數計時不如使用DispatchSourceTimer
它是和螢幕重新整理率同步,優點在於精確度高,適用於需要頻繁更新UI的場景。
var displayLink: CADisplayLink?
func startCountdown() {
    //一般倒數計時是操作UI,使用主佇列
    let displayLink = CADisplayLink(target: self, selector: #selector(update))
    //設定多長時間回撥一次,預設每次重新整理都會呼叫,大概60ps, 這裡設定1表示1s呼叫一次
    displayLink.preferredFramesPerSecond = 1
    displayLink.add(to: .main, forMode: .common)
}

@objc func update() {
    // 定時器執行的操作
}

deinit {
    displayLink.invalidate()
    displayLink = nil
}
Timer定時器
Timer定時器可以使用Timer.scheduledTimer方法建立,然後指定重複間隔和一個閉包作為定時器要執行的操作。並且將返回的定時器物件儲存在變數timer中。
要停止定時器,可以呼叫timer.invalidate()方法。
Timer是一個簡單的定時器,基於RunLoop的,通常用於實現對實時性要求不高的場合,因為它被註冊在runloop的timers事件源集合中,如果當前runloop執行耗時任務超過了呼叫時間,那麼就會丟棄當前次,直接執行下一次。導致定時器不準時的情況。
var timer: Timer?
func startCountdown() {
    //一般倒數計時是操作UI,使用主佇列
    timer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { timer in
    // 定時器執行的操作
    }
}

deinit {
    timer.invalidate()
    timer = nil
}

 

相關文章