我们使用RxSwift中的定时器时需要传一个scheduler
参数(有关使用可查看RxSwift中的定时器),我们会困惑应该创建哪个scheduler
合适(我称为调度器)。接下来我们来了解一下RxSwift中的调度器,下图是整理的类结构图

一、ImmediateSchedulerType
ImmediateSchedulerType
是protocol
类型的,内部有两个方法:
出现RecursiveImmediateScheduler
类是用来递归调用action。
/// 等待继承协议的必须实现
func schedule<StateType>(_ state: StateType, action: @escaping (StateType) -> Disposable) -> Disposable
/// 协议中实现的方法,使用RecursiveImmediateScheduler调度器来完成递归调用action
public func scheduleRecursive<State>(_ state: State, action: @escaping (_ state: State, _ recurse: (State) -> Void) -> Void) -> Disposable {
let recursiveScheduler = RecursiveImmediateScheduler(action: action, scheduler: self)
recursiveScheduler.schedule(state)
return Disposables.create(with: recursiveScheduler.dispose)
}
二、OperationQueueScheduler
OperationQueueScheduler
类创建实例时需要指定一个OperationQueue
和任务的优先级queuePriority
,在后续使用这个调度器调度任务时,我们的action都会放在一个BlockOperation
的block中,并且设置BlockOperation的优先级为实例的queuePriority
,然后把opt添加到queue中执行。
作用:使用这个调度器调度任务时,任务会在指定的queue中以指定的优先级执行。
// 使用递归调用的一个示例
let queue = OperationQueue()
queue.maxConcurrentOperationCount = 1// 串行队列
let scheduler = OperationQueueScheduler(operationQueue: queue)
// 递归调用的作用
_ = scheduler.scheduleRecursive(1) { state, action in
print("调用一次---------》")
if state < 6 {
action(state + 1)
} else {
print("state大于临界值")
}
}
三、CurrentThreadScheduler
CurrentThreadScheduler
调度器,特别之处在于:如果当前任务代码里面又开启一个新的任务,这个情况CurrentThreadScheduler
会将先将任务包装成ScheduledItem
加到队列中,等执行完当前任务后,遍历队列中的任务,逐个调用。 RxSwift 利用线程特有数据(TSD)解决循环调用的问题
四、SchedulerType
SchedulerType
是一个协议,有以下1个必须实现 + 1个可选实现 + 1个递归调度的方法.
下面代码中的SchedulePeriodicRecursive
类中调用start()
时是会调用下面的scheduleRecursive
方法; AnyRecursiveScheduler
类的实例执行它的schedule
方法时, 内部又会回调self.scheduler.scheduleRelative
方法。可以看到SchedulerType相比它继承的协议是多了对定时任务调度的支持。
/// 用于经过dueTime的相对时间后执行action,继承的类需要自己实现。
func scheduleRelative<StateType>(_ state: StateType, dueTime: RxTimeInterval, action: @escaping (StateType) -> Disposable) -> Disposable
/// 协议中可选实现方法,周期性调用action
public func schedulePeriodic<StateType>(_ state: StateType, startAfter: RxTimeInterval, period: RxTimeInterval, action: @escaping (StateType) -> StateType) -> Disposable {
let schedule = SchedulePeriodicRecursive(scheduler: self, startAfter: startAfter, period: period, action: action, state: state)
return schedule.start()
}
/// 协议中实现的方法,使用AnyRecursiveScheduler来完成对action的dueTime后递归调用
func scheduleRecursive<State>(_ state: State, dueTime: RxTimeInterval, action: @escaping (State, AnyRecursiveScheduler<State>) -> Void) -> Disposable {
let scheduler = AnyRecursiveScheduler(scheduler: self, action: action)
scheduler.schedule(state, dueTime: dueTime)
return Disposables.create(with: scheduler.dispose)
}
五、ConcurrentDispatchQueueScheduler
遵守SchedulerType协议 ,用于在并发队列中调度任务的,初始化这个实例时会创建并发队列,而后在调用协议中的几个schedule...
方法时,会在并发队列中执行它的任务。
public final func schedule<StateType>(_ state: StateType, action: @escaping (StateType) -> Disposable) -> Disposable {
self.configuration.schedule(state, action: action)
}
public final func scheduleRelative<StateType>(_ state: StateType, dueTime: RxTimeInterval, action: @escaping (StateType) -> Disposable) -> Disposable {
self.configuration.scheduleRelative(state, dueTime: dueTime, action: action)
}
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)
}
六、ConcurrentMainScheduler
这个类设计为了单例模式,与ConcurrentDispatchQueueScheduler
的区别在于任务会在主线程执行,可以看到如下的schedule方法:判断当前如果是主线程则直接执行action
, 如果不是则回到主线程中调用action。
/// Singleton instance of `ConcurrentMainScheduler`
public static let instance = ConcurrentMainScheduler(mainScheduler: MainScheduler.instance)
public func schedule<StateType>(_ state: StateType, action: @escaping (StateType) -> Disposable) -> Disposable {
if DispatchQueue.isMain { return action(state) }
let cancel = SingleAssignmentDisposable()
self.mainQueue.async {
if cancel.isDisposed {
return
}
cancel.setDisposable(action(state))
}
return cancel
}
七、SerialDispatchQueueScheduler
这个类通过名字我们可以知道是串行调度器,类似于串行队列。于ConcurrentDispatchQueueScheduler
的区别在于便利构造方法中,内部创建的是串行队列,执行action也是在这个串行队列中。
八、MainScheduler
这个调度器是继承自SerialDispatchQueueScheduler
的,用于在主线程中调度任务,我们主要使用它下面两个单例:
-
MainScheduler.instance
是MainScheduler
类型的, -
MainScheduler.asyncInstance
是SerialDispatchQueueScheduler
类型的;
这两个类型在执行schedule
方法时,都是转为调用scheduleInternal
方法,而两个类的scheduleInternal
中区别是:
-
MainScheduler
是判断当前是主线程会直接执行,不是主线程则异步回调到主线程执行action; -
SerialDispatchQueueScheduler
中是不管当前是否主线程,直接异步回调到主线程再执行。
/// Singleton instance of `MainScheduler`
public static let instance = MainScheduler()
/// Singleton instance of `MainScheduler` that always schedules work asynchronously
/// and doesn't perform optimizations for calls scheduled from main queue.
public static let asyncInstance = SerialDispatchQueueScheduler(serialQueue: DispatchQueue.main)
override func scheduleInternal<StateType>(_ state: StateType, action: @escaping (StateType) -> Disposable) -> Disposable {
let previousNumberEnqueued = increment(self.numberEnqueued)
if DispatchQueue.isMain && previousNumberEnqueued == 0 {
let disposable = action(state)
decrement(self.numberEnqueued)
return disposable
}
let cancel = SingleAssignmentDisposable()
self.mainQueue.async {
if !cancel.isDisposed {
cancel.setDisposable(action(state))
}
decrement(self.numberEnqueued)
}
return cancel
}
九、VirtualTimeScheduler
虚拟时间调度器基类,在使用时首先需要自己手写一个实现VirtualTimeConverterType
协议的类作为虚拟与真实的转化器;
调度任务的过程:先将时间转化为虚拟时间 --》 把任务组装成带时间戳的VirtualSchedulerItem
任务项 --》放到内部的PriorityQueue
队列中 --》调用start()方法后,在主线程中遍历PriorityQueue
调用每个action,并且每执行action前将self.currentClock
设置为action.time
。
这个调度器的特别的作用是PriorityQueue
队列中保存了调用记录和当前的调用进度。
// 需要子类实现自己的虚拟时间与真实时间转化的协议VirtualTimeConverterType
open class VirtualTimeScheduler<Converter: VirtualTimeConverterType>
: SchedulerType
十、HistoricalScheduler
继承自VirtualTimeScheduler
, 是一个有着自己的虚拟与真实时间转化器HistoricalSchedulerTimeConverter
的一个特例。
网友评论