RxSwift之Timer使用探究
复习
作为swift的初学者,说实话对于swift的使用还是比较欠缺的,日常开发使用的机会比较少,也就最近刚开始看了一部分,所以对于一些基础的swift的使用还是有必要的联系的,写博客也是一个机会
swift中的timer的使用
// normal写法 需要手动添加到loop
let timer_1 = Timer.init(timeInterval: 1, target: self, selector: #selector(runTimer1) , userInfo: nil, repeats: true)
RunLoop.current.add(timer_1, forMode: .common)
// block写法 需要手动添加到loop
let timer_2 = Timer.init(timeInterval: 1, repeats: true) { (timer) in
print("timer2 runing \(timer)")
}
RunLoop.current.add(timer_2, forMode: .common)
// 默认添加到loop中
_ = Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { (Timer) in
print("timer3 runing \(Timer)")
}
// GCD 写法
let gcdTimer = DispatchSource.makeTimerSource()
gcdTimer.schedule(deadline: DispatchTime.now(), repeating: DispatchTimeInterval.seconds(2))
gcdTimer.setEventHandler {
print("gcd timer running...")
}
gcdTimer.resume()
// CADisplayLink
let displayTimer = CADisplayLink(target: self, selector: #selector(displayTimerRun))
displayTimer.preferredFramesPerSecond = 1
displayTimer.add(to: RunLoop.current, forMode: .common)
RxSwift中的定时器的使用
// Rxswift
let _ = Observable<Int>.interval(1, scheduler: MainScheduler())
.subscribe(
onNext: { (count) in
print("定阅RxSwift \(count)")
}, onError: { (error) in
print("错误 RxSwift \(error)")
}, onCompleted: {
print("定阅RxSwift finish")
})
.disposed(by: disposeBag)
代码分析
Rxswift的定时器的使用可以简单分析,里边肯定含有一个RxSwift自己的定时器,这个定时器内部肯定也维护了相关的loop的调度,并且在其中触发生成序列,然后触发我们定阅的相关事件
RxSwift的定时器代码调用
public static func interval(_ period: RxTimeInterval, scheduler: SchedulerType)
-> Observable<E> {
return Timer(
dueTime: period,
period: period,
scheduler: scheduler
)
}
由此可见Rxswift的定时器是一个返回序列,这个返回的序列供外部的subscribe定阅
进一步分析Timer的实现和代码结构
final private class Timer<E: RxAbstractInteger>: Producer<E> {
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<O: ObserverType>(_ observer: O, cancel: Cancelable) -> (sink: Disposable, subscription: Disposable) where O.E == E {
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是继承自Producer的序列,这是创建可观察序列的过程。Timer也是遵循泛型E的协议,泛型E是RxAbstractInteger,它是FixedWidthInteger的别名,FixedWidthInteger顾名思义固定宽度的整数,我的理解就是相邻整数之间的是有固定宽度的
下面的订阅和RxSwift的核心逻辑相似
在订阅后都会走到对应类型的run方法,此时timer中的run方法如下:
override func run<O: ObserverType>(_ observer: O, cancel: Cancelable) -> (sink: Disposable, subscription: Disposable) where O.E == E {
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)
}
}
这里的逻辑页和Rxswift核心逻辑相似,只不过是生成了TimerSink或者TimerOneOffSink两种sink,sink会调用他们的run,以TimerSink为例:
final private class TimerSink<O: ObserverType> : Sink<O> where O.E : RxAbstractInteger {
typealias Parent = Timer<O.E>
private let _parent: Parent
private let _lock = RecursiveLock()
init(parent: Parent, observer: O, cancel: Cancelable) {
self._parent = parent
super.init(observer: observer, cancel: cancel)
}
func run() -> Disposable {
return self._parent._scheduler.schedulePeriodic(0 as O.E, startAfter: self._parent._dueTime, period: self._parent._period!) { state in
self._lock.lock(); defer { self._lock.unlock() }
self.forwardOn(.next(state))
return state &+ 1
}
}
}
分析run中的逻辑是取到Timer中的调度器执行schedulePeriodic,这个方法中的参数是两个时间间隔,和一个逃逸尾随闭包,这个方法是在MainScheduler的父类SerialDispatchQueueScheduler实现的,细节如下
/**
Schedules a periodic piece of work.
- parameter state: State passed to the action to be executed.
- parameter startAfter: Period after which initial work should be run.
- parameter period: Period for running the work periodically.
- parameter action: Action to be executed.
- returns: The disposable object used to cancel the scheduled action (best effort).
*/
public func schedulePeriodic<StateType>(_ state: StateType, startAfter: TimeInterval, period: TimeInterval, action: @escaping (StateType) -> StateType) -> Disposable {
return self.configuration.schedulePeriodic(state, startAfter: startAfter, period: period, action: action)
}
进一步进入
func schedulePeriodic<StateType>(_ state: StateType, startAfter: TimeInterval, period: TimeInterval, action: @escaping (StateType) -> StateType) -> Disposable {
let initial = DispatchTime.now() + dispatchInterval(startAfter)
var timerState = state
let timer = DispatchSource.makeTimerSource(queue: self.queue)
timer.schedule(deadline: initial, repeating: dispatchInterval(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
}
这里清晰的看到内部有一个GCD定时器,不断的将计时器相关的操作通过action传递出去给订阅者。