RxSwift中的Timer
我们在项目中经常会用到定时器,先来看下 swift
中使用定时器的几种方式:
Timer
//第一种写法 timer1 = Timer.init(timeInterval: 1, target: self, selector: #selector(timerFire),userInfo: nil, repeats: true) RunLoop.current.add(timer1, forMode: .common) //第二种写法 timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true, block: { (timer) inprint("定时中。。。") }) RunLoop.current.add(timer, forMode: .common)复制代码
这两种只是写法不同而已,第一种初始化的方式创建的 timer
需要手动添加到 runloop
中才能启动。第二种 scheduled
开头的方法,会默认把 timer
加入到当前 runloop
的 default
模式下。但它们都需要改成 common
模式, runloop
才会在滚动视图时同时也响应定时器。这个 timer
的生命周期以及内存泄漏风险都需要我们自己管理。
CADisplayLink
displayLink = CADisplayLink(target: self, selector: #selector(timerFire))displayLink?.preferredFramesPerSecond = 1 displayLink?.add(to: RunLoop.current, forMode: .common)复制代码
CADisplayLink
跟 Timer
差不多,是根据屏幕刷新频率来的,也是需要添加在 common
模式下。
DispatchSourceTimer
gcdTimer = DispatchSource.makeTimerSource() gcdTimer?.schedule(deadline: DispatchTime.now(), repeating: DispatchTimeInterval.seconds(1)) gcdTimer?.setEventHandler(handler: {print("定时中。。。") }) gcdTimer?.resume()复制代码
CGD中的定时器在使用时,不受主线程 runloop
的影响。它会在自己所在的线程中一直执行下去,直到你 suspend
或者 cancel
掉它。而且还可以指定 handler
所执行的线程。
RxSwift的Timer
let _ = Observable.interval(RxTimeInterval.seconds(1), scheduler: MainScheduler()) .subscribe(onNext: { (state) inprint(state) }) .disposed(by: disposeBag)复制代码
首先,这个 timer
也是不用关心 runloop
方面的问题。
进去看看这个 interval
函数:
public static func interval(_ period: RxTimeInterval, scheduler: SchedulerType) -> Observable{return Timer( dueTime: period, period: period, scheduler: scheduler ) }复制代码
参数1: RxTimeInterval
,就是 DispatchTimeInterval
的别名。 public typealias RxTimeInterval = DispatchTimeInterval
参数2:调度者, MainScheduler()
的视线中能看出,我们创建的是一个主线程调度者。
public init() { self._mainQueue = DispatchQueue.main super.init(serialQueue: self._mainQueue) }复制代码
返回值是一个初始化的 Timer
对象, timer
中保存了这些参数值,到此为止。
final private class Timer: Producer{ 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 } }复制代码
这个 timer
是 Producer
的子类,也是一个序列。 timer
中的泛型要求遵守 RxAbstractInteger
协议的。这个协议也是个别名, public typealias RxAbstractInteger = FixedWidthInteger
, FixedWidthInteger
协议要求遵守它的实例都是用固定大小的整数类型。所以我们在创建序列的时候把泛型指定为 Int
。
在创建了 timer
后,我们又进行了订阅,熟悉 RxSwift核心逻辑 的话,就会清楚订阅信号后,内部会创建一个匿名的观察者,然后返回创建的销毁者中会调用 timer序列
的订阅函数,这里又根据你指定的线程在不同的分支中走了 timer序列
的 run
:
func run(_ observer: Observer, cancel: Cancelable) -> (sink: Disposable, subscription: Disposable) {if self._period != nil {let sink = TimerSink(parent: self, observer: observer, cancel: cancel)let subscription = sink.run()return (sink: sink, subscription: subscription) } else { ...... } }复制代码
这里还是 RxSwift核心逻辑 熟悉的路子,创建 TimerSink
并调用 run
:
final private class TimerSink: Sinkwhere Observer.Element : RxAbstractInteger { typealias Parent = Timerprivate 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 inself._lock.lock(); defer { self._lock.unlock() } self.forwardOn(.next(state))return state &+ 1 } } }复制代码
run
里面主要就是 schedulePeriodi
,起始时间默认为0,后面两个都是 timer序列
的间隔时间,最后还有个闭包。这个函数会在我们外面设置的那个 主线程scheduler
中调用,为了防止多线程调用导致数据错误,这里加了线程锁。 state &+ 1
也对应了 FixedWidthInteger
协议,防止溢出。继续钻进去:
MainScheduler
的父类 SerialDispatchQueueScheduler
中 schedulePeriodi
的实现:
public func schedulePeriodic(_ state: StateType, startAfter: RxTimeInterval, period: RxTimeInterval, action: @escaping (StateType) -> StateType) -> Disposable {return self.configuration.schedulePeriodic(state, startAfter: startAfter, period: period, action: action) }复制代码
又是一个接口:
func schedulePeriodic(_ state: StateType, startAfter: RxTimeInterval, period: RxTimeInterval, action: @escaping (StateType) -> StateType) -> Disposable {let initial = DispatchTime.now() + startAfter var timerState = statelet timer = DispatchSource.makeTimerSource(queue: self.queue) timer.schedule(deadline: initial, repeating: period, leeway: self.leeway) var timerReference: DispatchSourceTimer? = timerlet cancelTimer = Disposables.create { timerReference?.cancel() timerReference = nil } timer.setEventHandler(handler: {if cancelTimer.isDisposed {return} timerState = action(timerState) }) timer.resume() return cancelTimer }复制代码
看到这里一下就明白了,从刚开始的参数类型开始就一直和GCD有关联,原来就是用序列封装了 DispatchSourceTimer
,在定时器触发时发送序列的 .next
信号。在序列销毁时 cancel
掉 timer
。
