RxSwift定时器探索

2019-07-31  本文已影响0人  简_爱SimpleLove

定时器创建

RxSwift中定时器的创建有两种方式:

        var a = 0
        // 通过interval创建
        timerO = Observable<Int>.interval(1, scheduler: MainScheduler.instance)
        timerO.subscribe(onNext: { (num) in
            a += 1
            if a > 5 {
                self.disposeBag = DisposeBag()
            }
            print(num)
        }, onError: { (error) in
            print(error)
        }, onCompleted: {
            print("完成")
        })
        .disposed(by: disposeBag)
        
        // 通过timer创建 
        // 第一个参数是:多长时间过后开始定时器
        Observable<Int>.timer(5, period: 1, scheduler: MainScheduler.instance)
            .subscribe(onNext: { (num) in
                print(num)
            })
        .disposed(by: disposeBag)

从上可以知道,可以通过timerinterval创建,由源代码可知,两个都是返回的一个Timer序列,只是通过timer创建的,多了一个dueTime参数。

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

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

并且测试发现定时器都不受UIScrollView或者UITableView的影响,也就是说当滑动UIScrollView或者UITableView时,定时器依然在走。让人不禁好奇,它具体是怎么做到的呢?

定时器探索

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 {  // _period != nil 有间隔时间,即执行多次,用TimerSink来管理
            let sink = TimerSink(parent: self, observer: observer, cancel: cancel) // 初始化sink
            let subscription = sink.run()
            return (sink: sink, subscription: subscription)
        }
        else { // 因为_period是RxTimeInterval?可选类型,这里是当 _period==nil 的情况,即执行一次,用TimerOneOffSink来管理
            let sink = TimerOneOffSink(parent: self, observer: observer, cancel: cancel)
            let subscription = sink.run()
            return (sink: sink, subscription: subscription)
        }
    }
}

以上是Timer的源码,从中可以知道:

sink.run()

    func run() -> Disposable {
        // 第一个参数默认传的 0 ,即从 0 开始计数,并且转为 Observer.Element 类型
        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
        }
    }

在这个方法中返回的是一个_schedulerschedulePeriodic方法,后面是跟的四个参数,其中的大括号是当做一个尾随闭包传过去的。

点击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)  // 初始化了一个DispatchSource,即是一个GCD定时器
        // deadline:开始时间  repeating:调用间隔 leeway:允许误差范围
        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 {  // 只有当Disposables创建的时候才能销毁定时器,所以上面的ToDo说horrible
            timerReference?.cancel()
            timerReference = nil
        }

        timer.setEventHandler(handler: {   // 保存事件
            if cancelTimer.isDisposed {    // 当Disposables已经被创建的时候就返回,不再调用定时器方法
                return
            }
            timerState = action(timerState) // 发送状态,调用闭包action,赋值timerState,即来到了定时器的下一次方法
        })
        timer.resume()   // 启动定时器
        
        return cancelTimer
    }
let timer = DispatchSource.makeTimerSource(queue: self.queue)
 timer.schedule(deadline: initial, repeating: period, leeway: self.leeway)

可知,timer是一个GCD定时器

后续流程

1、走到action闭包,然后就来到了self.forwardOn(.next(state))这个方法
2、然后来到Sink中的self._observer.on(event)这个方法,这里的self._observer即是timer序列
3、然后来到onNext?(value)方法,也就是来到外面subscribe方法的onNext

            .subscribe(onNext: { (num) in
                print(num)
            })

4、这样第一个定时器事件走完,然后再在action中传下一个state,执行下一次事件

总结
RxSwift中的定时器是对GCD定时器的封装,也即是将定时器封装成了一个可观察序列,每次定时发送一个定时器事件,通过sink来管理序列和订阅者之间的通信。并且只有Disposables.create才能销毁定时器。

上一篇下一篇

猜你喜欢

热点阅读