我們使用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
方法。
/// 用於經過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
的一個特例。