美文网首页
RxSwift定时器探索

RxSwift定时器探索

作者: 简_爱SimpleLove | 来源:发表于2019-07-31 17:33 被阅读0次

    定时器创建

    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的源码,从中可以知道:

    • Timer在初始化的时候,保存了传进来的三个参数
    • 因为_periodRxTimeInterval?可选类型,所以单独用TimerOneOffSink来处理当_period等于nil的情况
    • 可以看出Timer继承自Producer,由上篇文章可知,最终会走到sink.run()方法

    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定时器

    • 由TODO可知,只有Disposables.create的时候才能取消定时器
    • 定时器事件,是反复调用闭包action,给action传上一个的timerState,从而返回下一个的timerState,并将状态保存下来
    • action闭包即sink.run()中传过去的闭包
    • 定时器的方法,即反复走这个闭包,每次都是不同的state

    后续流程

    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才能销毁定时器。

    相关文章

      网友评论

          本文标题:RxSwift定时器探索

          本文链接:https://www.haomeiwen.com/subject/bwttdctx.html