RxSwift是一个比较大的框架,如果我们项目使用了这个框架的话,可以尽量去使用里面封装的一些功能,比如定时器Timer
。
首先说明源码中提供的定时器方法有2个:
// 开启一个定时器:在dueTime后,每隔period在scheduler中发送一次onNext:
// 这里的period如果为空,则是一个一次性的timer,触发一次之后就结束
public static func timer(_ dueTime: RxSwift.RxTimeInterval, period: RxSwift.RxTimeInterval? = nil, scheduler: RxSwift.SchedulerType) -> RxSwift.Observable<Self.Element>
// 本方法是上面方法中dueTime = period的情况
public static func interval(_ period: RxSwift.RxTimeInterval, scheduler: RxSwift.SchedulerType) -> RxSwift.Observable<Self.Element>
因为上述两个方法的区别较小,所以这里以interval
方法为例:
一、使用方法
开启定时器一般分为在主线程、子线程两种情况:
RxSwift中的Scheduler
var timerDispose: Disposable?
/// 1. 在主线程开启定时器,并且在主线程回调onNext:
/// 定时器销毁的时机在:信号执行dispose之后(disposeBag销毁、onError、onComplete)
timerDispose = Observable<Int>.interval(.seconds(1), scheduler: MainScheduler.instance)
.subscribe(onNext: { num in
print(Thread.current, "subscribe===>", num)
})
timerDispose.disposed(by: self.disposeBag) // 在自身销毁时销毁定时器
// timerDispose.dispose() // 手动销毁定时器的方法
/// 2. 在子线程开启定时器,并且在子线程回调onNext:
timerDispose = Observable<Int>.interval(.seconds(2), scheduler: SerialDispatchQueueScheduler(internalSerialQueueName: "testTimer"))
.subscribe(onNext: { num in // num会调用一次加1
print(Thread.current, "===>", num)
DispatchQueue.main.async {
print("testTimer:回到主线程做事", Thread.current)
}
})
timerDispose.disposed(by: self.disposeBag) // 在自身销毁时销毁定时器
// timerDispose.dispose() // 手动销毁定时器的方法
二、RxSwift中定时器的大体过程
- 创建RxSwift中的Timer对象并返回
public static func interval(_ period: RxTimeInterval, scheduler: SchedulerType)
-> Observable<Element> {
return Timer(dueTime: period, period: period, scheduler: scheduler )
}
--》2. 在Timer
被订阅(subscribe
)时,首先会创建一个AnonymousObserver
类型的匿名observer
, 返回一个Disposable
, 里面的self.asObservable().subscribe(observer),
中self是Timer实例,继承自Producer
类,所以会执行Producer
类的subscribe
方法。
public func subscribe( onNext: ((Element) -> Void)? = nil, onError: ((Swift.Error) -> Void)? = nil, onCompleted: (() -> Void)? = nil, onDisposed: (() -> Void)? = nil
) -> Disposable {
let disposable: disposable = Disposables.create()
let observer = AnonymousObserver<Element> { event in
switch event {
case .next(let value):
onNext?(value)
case .error(let error):// 省略
case .completed:// 省略
}
}
return Disposables.create(
self.asObservable().subscribe(observer), // 这里的self是Timer
disposable
)
}
--》3. 接下来会执行Timer的父类Producer
中subscribe
方法,然后执行Timer
的run
方法。如下代码中CurrentThreadScheduler.instance.schedule
函数内部主要逻辑是调用这个尾随闭包,闭包中会调用self.run(observer, cancel: disposer)
, 这里的self还是Timer。
/// Producer中subscribe
override func subscribe<Observer: ObserverType>(_ observer: Observer) -> Disposable where Observer.Element == Element {
return CurrentThreadScheduler.instance.schedule(()) { _ in
let disposer = SinkDisposer()
let sinkAndSubscription = self.run(observer, cancel: disposer)
disposer.setSinkAndSubscription(sink: sinkAndSubscription.sink, subscription: sinkAndSubscription.subscription)
return disposer
}
}
/// 这里是Timer的run方法
override func run<Observer: ObserverType>(_ observer: Observer, cancel: Cancelable) -> (sink: Disposable, subscription: Disposable) where Observer.Element == Element {
if self.period != nil {
let sink = TimerSink(parent: self, observer: observer, cancel: cancel)
let subscription = sink.run()
return (sink: sink, subscription: subscription)
}
else {// 一次性的定时器,这里略 }
}
--》 4. 接下来是TimerSink
的实例调用sink.run()
, 可以看到内部是执行scheduler的schedulePeriodic
方法,方法最后一个参数action
是尾随闭包,这里的scheduler
是我们创建定时器时创建的,因为MainScheduler
是继承SerialDispatchQueueScheduler
的,所以这里以后者来追踪。可以看到会转给scheduler内部的configuration执行schedulePeriodic
方法
func run() -> Disposable {
return self.parent.scheduler.schedulePeriodic(0 as Observer.Element, startAfter: self.parent.dueTime, period: self.parent.period!) { state in
self.lock.performLocked {
self.forwardOn(.next(state))
return state &+ 1 // 调用一次之后让state+1,这样在订阅next里面的num会每次加1
}
}
}
/// SerialDispatchQueueScheduler中的schedulePeriodic方法,会转给
public func schedulePeriodic<StateType>(_ state: StateType, startAfter: RxTimeInterval, period: RxTimeInterval, action: @escaping (StateType) -> StateType) -> Disposable {
self.configuration.schedulePeriodic(state, startAfter: startAfter, period: period, action: action)
}
--》5. scheduler内部的configuration执行schedulePeriodic
方法的逻辑, 可以看到内部是在self.queue
中创建了一个TimerSource
, 定时器每次触发时,会执行timerState = action(timerState)
即第4步中传进来的action, 可以看到是会执行self.forwardOn(.next(state))
, 即发送一个next事件 --> 最终使用者收到onNext
调用.
func schedulePeriodic<StateType>(_ state: StateType, startAfter: RxTimeInterval, period: RxTimeInterval, action: @escaping (StateType) -> StateType) -> Disposable {
let initial = DispatchTime.now() + startAfter
var timerState = state
// self.queue是在scheduler创建时内部创建的,所以是不是主线程取决于创建scheduler的类型
let timer = DispatchSource.makeTimerSource(queue: self.queue)
timer.schedule(deadline: initial, repeating: period, leeway: self.leeway)
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
}
--》 6. 我们在使用时如果对时间准确度要求比较高的可以使用MainScheduler.instance
; 如果对时间准确度要求高的可以使用SerialDispatchQueueScheduler(internalSerialQueueName: "testTimer")
三、 销毁定时器
销毁定时器的方法:
使用定时器时引用返回的Disposable,在不需要定时器时执行dispose即可
原理:
可以看到在上述第2步中,创建匿名observer时会返回Disposable, 内部是引用了匿名observer的,在Disposable执行dispose时,observer也会失去引用而销毁; 然后在上述的第5步中可以看到cancelTimer
在执行dispose
时,会执行timerReference?.cancel() ; timerReference = nil
。
四、 使用系统定时器
系统定时器:
1、系统封装的Timer
,使用起来跟NSTimer是一样的。
2、系统的GCDTiemr,使用方法跟第5步是一样的, 缺少了当前是第几次触发的功能。
我更倾向于使用RxSwift中定时器是因为以下几个原因:
- 使用也很简单方便
- 能够知道当前是第几次定时触发