用RxSwift可以这样表示:
let rxData: Observable<Data> = ...
rxData
.subscribeOn(ConcurrentDispatchQueueScheduler(qos: .userInitiated))
.observeOn(MainScheduler.instance)
.subscribe(onNext: { [weak self] data in
self?.data = data
})
.disposed(by: disposeBag)
-
subscribeOn
subscribeOn
来决定数据序列的构建函数在哪个 Scheduler
上运行。由于获取 Data
为耗时操作,所以用 subscribeOn
切换到后台 Scheduler
来获取 Data
。这样可以避免主线程被阻塞。
-
observeOn
用 observeOn
来决定在哪个 Scheduler
监听这个数据序列。例子中,通过使用 observeOn
方法切换到主线程来监听并且处理结果。
RxSwift
中提供了几种常用的调度器:
-
MainScheduler
MainScheduler
代表主线程。如果需要执行一些和 UI 相关的任务,就需要切换到该 Scheduler
运行。
public final class MainScheduler : SerialDispatchQueueScheduler {
private let _mainQueue: DispatchQueue
let numberEnqueued = AtomicInt(0)
/// Initializes new instance of `MainScheduler`.
public init() {
self._mainQueue = 'DispatchQueue.main'
super.init(serialQueue: self._mainQueue)
}
/// Singleton instance of `MainScheduler`
public static let instance = MainScheduler()
}
代码中非常明显的看到self._mainQueue = 'DispatchQueue.main
初始化时绑定了主队列。
-
ConcurrentMainScheduler
这个scheduler
对subscibeOn
操作符有优化,所以,如果希望elemen
t的产生在主线程上,那么用ConcurrentMainScheduler
。
public final class ConcurrentMainScheduler : SchedulerType {
private let _mainScheduler: MainScheduler
private let _mainQueue: DispatchQueue
private init(mainScheduler: MainScheduler) {
self._mainQueue = DispatchQueue.main // 主队列
self._mainScheduler = mainScheduler
}
/// Singleton instance of `ConcurrentMainScheduler`
public static let instance = ConcurrentMainScheduler(mainScheduler: MainScheduler.instance)
}
-
SerialDispatchQueueScheduler
SerialDispatchQueueScheduler
抽象了串行 DispatchQueue
。如果需要执行一些串行任务,可以切换到这个 Scheduler
运行它能够保证即使你传入的是一个并发的队列,它也会把他转化成串行的。
public class SerialDispatchQueueScheduler : SchedulerType {
let configuration: DispatchQueueConfiguration
init(serialQueue: DispatchQueue, leeway: DispatchTimeInterval = DispatchTimeInterval.nanoseconds(0)) {
self.configuration = DispatchQueueConfiguration(queue: serialQueue, leeway: leeway)
}
public convenience init(internalSerialQueueName: String, serialQueueConfiguration: ((DispatchQueue) -> Void)? = nil, leeway: DispatchTimeInterval = DispatchTimeInterval.nanoseconds(0)) {
let queue = DispatchQueue(label: internalSerialQueueName, attributes: [])
serialQueueConfiguration?(queue)
self.init(serialQueue: queue, leeway: leeway)
}
}
SerialDispatchQueueScheduler
为我们提供了多种便利构造器来初始化一个串行队列。
-
ConcurrentDispatchQueueScheduler
ConcurrentDispatchQueueScheduler
抽象了并行 DispatchQueue
。如果需要执行一些并发任务,可以切换到这个 Scheduler
运行。
public class ConcurrentDispatchQueueScheduler: SchedulerType {
let configuration: DispatchQueueConfiguration
public init(queue: DispatchQueue, leeway: DispatchTimeInterval = DispatchTimeInterval.nanoseconds(0)) {
self.configuration = DispatchQueueConfiguration(queue: queue, leeway: leeway)
}
@available(iOS 8, OSX 10.10, *)
public convenience init(qos: DispatchQoS, leeway: DispatchTimeInterval = DispatchTimeInterval.nanoseconds(0)) {
self.init(queue: DispatchQueue(
label: "rxswift.queue.\(qos)",
qos: qos,
attributes: [DispatchQueue.Attributes.concurrent],
target: nil),
leeway: leeway
)
}
}
-
OperationQueueScheduler
抽象了 NSOperationQueue
。
它具备 NSOperationQueue
的一些特点,可以通过设置优先级和最大并发任务数量(maxConcurrentOperationCount)。
public class OperationQueueScheduler: ImmediateSchedulerType {
public let operationQueue: OperationQueue
public let queuePriority: Operation.QueuePriority
public init(operationQueue: OperationQueue, queuePriority: Operation.QueuePriority = .normal) {
self.operationQueue = operationQueue
self.queuePriority = queuePriority
}
}
-
CurrentThreadScheduler
还有一个默认使用的调度器--当前调度器CurrentThreadScheduler
public class CurrentThreadScheduler : ImmediateSchedulerType {
typealias ScheduleQueue = RxMutableBox<Queue<ScheduledItemType>>
/// The singleton instance of the current thread scheduler.
public static let instance = CurrentThreadScheduler()
private static var 'isScheduleRequiredKey': pthread_key_t = { () -> pthread_key_t in
let key = UnsafeMutablePointer<pthread_key_t>.allocate(capacity: 1)
defer { key.deallocate() }
guard pthread_key_create(key, nil) == 0 else {
rxFatalError("isScheduleRequired key creation failed")
}
return key.pointee
}()
private static var scheduleInProgressSentinel: UnsafeRawPointer = { () -> UnsafeRawPointer in
return UnsafeRawPointer(UnsafeMutablePointer<Int>.allocate(capacity: 1))
}()
static var 'queue' : ScheduleQueue? {
get {
return Thread.getThreadLocalStorageValueForKey(CurrentThreadSchedulerQueueKey.instance)
}
set {
Thread.setThreadLocalStorageValue(newValue, forKey: CurrentThreadSchedulerQueueKey.instance)
}
}
/// Gets a value that indicates whether the caller must call a `schedule` method.
public static fileprivate(set) var 'isScheduleRequired': Bool {
get {
return pthread_getspecific(CurrentThreadScheduler.isScheduleRequiredKey) == nil
}
set(isScheduleRequired) {
if pthread_setspecific(CurrentThreadScheduler.isScheduleRequiredKey, isScheduleRequired ? nil : scheduleInProgressSentinel) != 0 {
rxFatalError("pthread_setspecific failed")
}
}
}
}
isScheduleRequiredKey
是拿到线程当前的key
通过对queue
的set
和 get
方法来实现我们的当前队列与静态字符串的绑定。
extension Thread {
static func setThreadLocalStorageValue<T: AnyObject>(_ value: T?, forKey key: NSCopying) {
let currentThread = Thread.current
let threadDictionary = currentThread.threadDictionary
if let newValue = value {
threadDictionary[key] = newValue
}
else {
threadDictionary[key] = nil
}
}
static func getThreadLocalStorageValueForKey<T>(_ key: NSCopying) -> T? {
let currentThread = Thread.current
let threadDictionary = currentThread.threadDictionary
return threadDictionary[key] as? T
}
}
isScheduleRequired
表示当前队列是否被关联,
当前线程没有被关联时isScheduleRequired
的返回值为true
。
当isScheduleRequired
设置为false
时三目运算将scheduleInProgressSentinel
赋值给线程的key
,表示队列被关联。
SchedulerType | description |
---|---|
MainScheduler | 代表主线程。执行一些和 UI 相关的任务 |
ConcurrentMainScheduler | 对subscibeOn操作符有优化,使望element的产生在主线程上 |
SerialDispatchQueueScheduler | 抽象了串行队列,执行一些串行任务 |
ConcurrentDispatchQueueScheduler | 抽象了并行 队列,执行一些并发任务 |
OperationQueueScheduler | 它具备 NSOperationQueue 的一些特点,可以设置优先级和最大并发数 |
CurrentThreadScheduler | 当前调度器,默认调度器 |
最后赋上一张调度器关系继承图: