RxSwift中的Scheduler

我們使用RxSwift中的定時器時需要傳一個scheduler參數(有關使用可查看RxSwift中的定時器),我們會困惑應該創建哪個scheduler合適(我稱爲調度器)。接下來我們來了解一下RxSwift中的調度器,下圖是整理的類結構圖

一、ImmediateSchedulerType

ImmediateSchedulerTypeprotocol類型的,內部有兩個方法:
出現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.instanceMainScheduler類型的,
  • MainScheduler.asyncInstanceSerialDispatchQueueScheduler類型的;

這兩個類型在執行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的一個特例。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章