RxSwift源碼分析(三)-timer的解析

在開發中,咱們會常常用到定時器,主要是用NSTimer實現的。但或多或少都遇到過一些問題,好比說觸發UI操做時定時器失效,循環引用、線程等問題。觸發UI操做時定時器失效是由於把timer加入到runloop的模式不對,關閉循環引用的問題能夠看以前寫的一篇文章防止NSTimer循環引用的幾個方法。固然咱們也能夠用GCD的定時器,CGD中的定時器計時更加精準,不受主線程runloop的影響。它會在本身所在的線程中一直執行下去,直到你suspend或者cancel掉它,並且還能夠指定handler所執行的線程。GCD定時器簡單實用的代碼:html

gcdTimer = DispatchSource.makeTimerSource(queue: DispatchQueue.main)
gcdTimer.schedule(deadline: DispatchTime.now(), repeating: DispatchTimeInterval.seconds(1))
gcdTimer.setEventHandler(handler: {
    print("gcd timer\(Thread.current)")
})
gcdTimer.resume()
複製代碼

RxSwift的timer實現

提示: 由於RxSwift的核心邏輯大體相同,因此前面文章講過的核心邏輯這裏不重複,只講不一樣的地方,還不太明白的朋友能夠先看這兩篇文章RxSwift源碼分析(一)-核心邏輯解析RxSwift源碼分析(二)-Observable和AnonymousObservableSink解析swift

言歸正傳,咱們一塊兒來看看RxSwift的timer是怎樣實現的。首先咱們須要探索RxSwift的timer在使用的過程當中有沒有如下幾個問題:api

  1. RxSwift的timer是否受runloop的影響
  2. 是否有循環引用的問題
  3. 是否須要關心線程問題

帶着問題,咱們進入RxSwift Timer的源碼分析bash

// 第一次參數:第一次響應距離如今的時間
// 第二個參數:時間間隔
// 第三個參數:線程
_ = Observable<Int>.timer(DispatchTimeInterval.seconds(0), period: DispatchTimeInterval.seconds(1), scheduler: MainScheduler.instance).subscribe { (event) in
    print(event)
}
複製代碼

如上,RxSwift Timer使用起來很是簡單。 先進入到Timer.swift文件找到timer方法, 這是一個ObservableType協議的的擴展方法,返回的是一個Timer對象,其類型是Observable。因此Timer也是一個可觀察序列,咱們能夠經過訂閱來接收觀察者發送的消息。多線程

public static func timer(_ dueTime: RxTimeInterval, period: RxTimeInterval? = nil, scheduler: SchedulerType)
        -> Observable<Element> {
        return Timer(
            dueTime: dueTime,
            period: period,
            scheduler: scheduler
        )
    }
複製代碼

咱們繼續跟蹤到Timer類裏面去看一看Timer究竟是怎麼實現的閉包

final private class Timer<Element: RxAbstractInteger>: Producer<Element> {
    fileprivate let _scheduler: SchedulerType
    fileprivate let _dueTime: RxTimeInterval
    fileprivate let _period: RxTimeInterval?

    init(dueTime: RxTimeInterval, period: RxTimeInterval?, scheduler: SchedulerType) {
        self._scheduler = scheduler
        self._dueTime = dueTime
        self._period = period
    }

    override func run<Observer: ObserverType>(_ observer: Observer, cancel: Cancelable) -> (sink: Disposable, subscription: Disposable) where Observer.Element == Element {
        if self._period != nil {
            let sink = TimerSink(parent: self, observer: observer, cancel: cancel)
            let subscription = sink.run()
            return (sink: sink, subscription: subscription)
        }
        else {
            let sink = TimerOneOffSink(parent: self, observer: observer, cancel: cancel)
            let subscription = sink.run()
            return (sink: sink, subscription: subscription)
        }
    }
}
複製代碼

在初始化的時候,保存了外面傳過來的三個參數。 在上面的示例中,先建立了timer對象,而後調用了subscribe方法進行了訂閱。若是看過上兩篇關於RxSwift核心邏輯分析的文章的話,咱們知道當調用了subscribe方法的以後,代碼會執行到Producer類的subscribe方法,而後執行到Timer類的run方法。在run方法中建立TimerSink對象並保持了Timer對象,而後執行sink.run,這個流程跟其餘序列的執行是同樣的。進入到TimerSink類裏面:ide

final private class TimerSink<Observer: ObserverType> : Sink<Observer> where Observer.Element : RxAbstractInteger  {
    typealias Parent = Timer<Observer.Element>

    private let _parent: Parent
    private let _lock = RecursiveLock()

    init(parent: Parent, observer: Observer, cancel: Cancelable) {
        self._parent = parent
        super.init(observer: observer, cancel: cancel)
    }

    func run() -> Disposable {
        return self._parent._scheduler.schedulePeriodic(0 as Observer.Element, startAfter: self._parent._dueTime, period: self._parent._period!) { state in
            self._lock.lock(); defer { self._lock.unlock() }
            self.forwardOn(.next(state))
            return state &+ 1
        }
    }
}
複製代碼

_parent就是Timer對象,而後一直跟蹤schedulePeriodic進入,最後會來到DispatchQueueConfiguration類的schedulePeriodic方法函數

func schedulePeriodic<StateType>(_ state: StateType, startAfter: RxTimeInterval, period: RxTimeInterval, action: @escaping (StateType) -> StateType) -> Disposable {
        let initial = DispatchTime.now() + startAfter

        var timerState = state

        let timer = DispatchSource.makeTimerSource(queue: self.queue)
        timer.schedule(deadline: initial, repeating: period, leeway: self.leeway)
        
        var timerReference: DispatchSourceTimer? = timer
        let cancelTimer = Disposables.create {
            timerReference?.cancel()
            timerReference = nil
        }

        timer.setEventHandler(handler: {
            if cancelTimer.isDisposed {
                return
            }
            timerState = action(timerState)
        })
        timer.resume()
        
        return cancelTimer
    }
複製代碼

能夠看到,RxSwift的timer實際上是封裝的DispatchSource定時器。當序列銷燬時會執行定時器的cancel方法取消來定時器。當定時器觸發時會調用action(timerState)這個代碼塊並保存代碼塊的返回值state(初始值爲0)。這個代碼塊就是以前調用TimerSink類的run方法時的尾隨閉包。這個函數會在咱們外面設置的那個主線程scheduler中調用,爲了防止多線程調用致使數據錯誤,這裏加了線程鎖。而後執行forwardOn這個方法,後面的流程又跟以前兩篇文章講過的RxSwift核心邏輯同樣,這裏就不講了。state是遵循FixedWidthInteger協議的變量,state &+ 1是位操做,每執行一次+1,&+運算符這種寫法能夠防止溢出,能夠參考文檔oop

總結

針對上面提出的問題總結一下:源碼分析

  • 由於RxSwift的timer是封裝的DispatchSource定時器是不會受runloop的影響的
  • DispatchSource並無直接引用self,因此不存在循環引用帶來的問題
  • 建立timer序列時,咱們必須指定一個MainScheduler實例,也就指定了代碼執行的線程。
相關文章
相關標籤/搜索