(二)RxSwift 之 Timer

884 阅读3分钟

一.swift中常见的几种定时器初始化方法:

1)第一种:常用定时器

let timer = Timer.init(timeInterval: 1, target: self, selector: #selector(firmTimer), userInfo: nil, repeats: true)
RunLoop.current.add(timer, forMode: .common)
@objc func firmTimer(){
    print("定时器")
}

2)第二种:CADisplayLink

let CATimer: CADisplayLink = CADisplayLink(target: self, selector: #selector(firmTimer))
CATimer.preferredFramesPerSecond = 1
CATimer.add(to: .current, forMode: .common)

3)第三种:DispatchSourceTimer

var gcdTimer: DispatchSource?
self.gcdTimer = DispatchSource.makeTimerSource() as? DispatchSource
self.gcdTimer?.schedule(deadline: DispatchTime.now(), repeating: DispatchTimeInterval.seconds(1))
self.gcdTimer?.setEventHandler(handler: {
    print("定时器")
})
self.gcdTimer?.resume()

⚠️GCDTimer有一点需要注意一下,因为 gcdTimer 是个局部变量,当函数执行完之后,会被自动释放,也就不会再执行handler的方法了,所以要写成全局变量。

对比三种方法:第一种和第二种会受到Runloop的影响,第三种不会。

二.来看一下RXSwift中的定时器

let timer = Observable<Int>.interval(DispatchTimeInterval.seconds(1), scheduler: MainScheduler.instance)
timer.subscribe(onNext: { (num) in
    print(num)
})
.disposed(by: disposeBag)

RXSwift 中的Timer不受Runloop的影响,让我们一起探究一下,它是如何实现的。

  • 首先来看Timer的创建
let timer = Observable<Int>.interval(DispatchTimeInterval.seconds(1), scheduler: MainScheduler.instance)

会来到TimerTimer.swift中的interval方法中

public static func interval(_ period: RxTimeInterval, scheduler: SchedulerType) -> Observable<Element> {
    return Timer(
        dueTime: period,
        period: period,
        scheduler: scheduler
    )
}

点进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初始化时将外界传来的schedulerdueTime, period保存为属性。

  • 再来看一下Timer的订阅
timer.subscribe(onNext: { (num) in
    print(num)
})

会来到ObservableType+Extensionssubscribe方法中

public func subscribe(onNext: ((Element) -> Void)? = nil, onError: ((Swift.Error) -> Void)? = nil, onCompleted: (() -> Void)? = nil, onDisposed: (() -> Void)? = nil)
        -> Disposable {
            let disposable: Disposable
            
            if let disposed = onDisposed {
                disposable = Disposables.create(with: disposed)
            }
            else {
                disposable = Disposables.create()
            }
            
            #if DEBUG
                let synchronizationTracker = SynchronizationTracker()
            #endif
            
            let callStack = Hooks.recordCallStackOnError ? Hooks.customCaptureSubscriptionCallstack() : []
            
            let observer = AnonymousObserver<Element> { event in
                
                #if DEBUG
                    synchronizationTracker.register(synchronizationErrorMessage: .default)
                    defer { synchronizationTracker.unregister() }
                #endif
                
                switch event {
                case .next(let value):
                    onNext?(value)
                case .error(let error):
                    if let onError = onError {
                        onError(error)
                    }
                    else {
                        Hooks.defaultErrorHandler(callStack, error)
                    }
                    disposable.dispose()
                case .completed:
                    onCompleted?()
                    disposable.dispose()
                }
            }
            return Disposables.create(
                self.asObservable().subscribe(observer),
                disposable
            )
    }   
}

初始化let observer = AnonymousObserver<Element> { event in的匿名观察者 AnonymousObserver 后面尾随闭包做参数。

return Disposables.create(
    self.asObservable().subscribe(observer),
    disposable
)

又会带我们来到父类的ProducerProducer中 -> 会回到自己的run方法中

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)
    }
 }

接下来就会来到TimerSink

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
        }
    }
}

看一下TimerSinkrun方法,返回一个self._parent._scheduler.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)
        
        // TODO:
        // This looks horrible, and yes, it is.
        // It looks like Apple has made a conceputal change here, and I`m unsure why.
        // Need more info on this.
        // It looks like just setting timer to fire and not holding a reference to it
        // until deadline causes timer cancellation.
        
        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
    }

let timer = DispatchSource.makeTimerSource(queue: self.queue)在这段代码中我们可以看出来用的GCD Timer,所以才不会收到runLoop的影响,

timer.setEventHandler(handler: {
    if cancelTimer.isDisposed {
        return
       }
    timerState = action(timerState)
})

Timer会不断的执行这个EventHandler中的timerState = action(timerState),让我们来看一下这个action是什么

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
    }
}

action 就是TimerSink中的run函数中的逃逸闭包啊

{ state in
    self._lock.lock(); defer { self._lock.unlock() }
    self.forwardOn(.next(state))
    return state &+ 1
}

这里的会调用self.forwardOn(.next(state))函数,并把state带过去, forwardOn我们熟悉的函数,之后的的流程和上一篇从创建到相应是一样的。

如何取消定时器:根据序列的特点可发送,错误,销毁,使timer停止。