定时器创建
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)
从上可以知道,可以通过timer和interval创建,由源代码可知,两个都是返回的一个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
在初始化的时候,保存了传进来的三个参数 - 因为
_period
是RxTimeInterval?
可选类型,所以单独用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
}
}
在这个方法中返回的是一个_scheduler
的schedulePeriodic
方法,后面是跟的四个参数,其中的大括号是当做一个尾随闭包传过去的。
点击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才能销毁定时器。
网友评论