RxSwift系列—RxSwift调度者

10 篇文章 0 订阅
9 篇文章 3 订阅

四、RxSwift调度者

4.1 案例引入

Schedulers 是RxSwift实现多线程的核心模块。它主要用于控制任务在哪个线程或队列运行。

咱们在平时的开发过程中,肯定都使用过网络请求,网络请求是在后台执行的,获取到数据之后,再在主线程更新UI。

先来一段代码引入

/// 子线程
DispatchQueue.global().async {
    print("请求数据")
   let _ = self.actionBtn.rx.tap
    .subscribe(onNext: { () in
        /// 主线程(通过线程调度,调度回来,切换线程)
        print("tap =--- \(Thread.current)")
    })
}

在这里插入图片描述
再来一段网络请求伪代码。

DispatchQueue.global(qos: .userInitiated).async {
    
    let data = try? Data(contentsOf: url)
    
    DispatchQueue.main.async {
        // 更新UI
    }
}

如果用RxSwift来实现上面的网络请求,则大致是这样的:

let rxData: Observable<Data> = ...

rxData
	.subscribeOn(ConcurrentDispatchQueueScheduler(qos: .userInitiated))
	.observeOn(MainScheduler.instance)
	.subscribe(onNext: { [weak self](data) in
    	// 更新UI
	})
	.disposed(by: disposeBag)

说明:

  1. 我们用 subscribeOn 来决定数据序列的构建函数在哪个 Scheduler 上运行。 在上面的例子中,由于获取 Data 需要花费很长的时间,所以用 subsribeOn 切换到 后台Scheduler 来获取 Data 。这样就可以避免阻塞主线程。
  2. 我们用 observeOn 来决定在哪个 Scheduler 监听这个数据序列。 在上面的例子中,通过 observerOn 方法切换到主线程来监听并处理结果。

4.2 MainScheduler

MainScheduler 代表 主线程。如果需要执行和UI相关的任务,就需要切换到该 Scheduler 运行。

在这里插入图片描述
可以清晰的知道,在初始化时,在 MainScheduler 对象的内部,绑定了主队列 DispatchQueue.main

4.3 SerialDispatchQueueScheduler

SerialDispatchQueueScheduler 抽象了 串行DispatchQueue。如果需要执行一些串行任务,可以切换到这个 Scheduler 执行。
在这里插入图片描述
在初始化 SerialDispatchQueueScheduler 对象时,需要传入一个 DispatchQueue,保存在 self.configuration 结构体中。

4.4 ConcurrentDispatchQueueScheduler

ConcurrentDispatchQueueScheduler 抽象了 并行DispatchQueue。如果需要执行一些并发任务,可以切换到这个 Scheduler执行。

在这里插入图片描述

4.5 OperationQueueScheduler

OperationQueueScheduler 抽象了 NSOperationQueue。它具备一些 NSOperationQueue 的特点。例如,可以通过设置 maxConcurrentOperationCount 来控制同时执行并发任务的最大数量。

在这里插入图片描述
在初始化 OperationQueueScheduler 对象时,需要传入 OperationQueue优先级queuePriority,作为初始化参数。

4.6 Scheduler的调度执行

从上一小节的几种调度器的源码可以发现,所有的调度器 Scheduler 都继承自 ImmediateSchedulerType 协议。
在这里插入图片描述
而这个协议只声明了一个 schedule 方法,而通过注释可以知道,在调度器调度执行的时候都会调用这个 schedule 方法。

咱们现在以 SerialDispatchQueueScheduler 调度器为例:

/**
Schedules an action to be executed immediately.

- parameter state: State passed to the action to be executed.
- parameter action: Action to be executed.
- returns: The disposable object used to cancel the scheduled action (best effort).
    */
public final func schedule<StateType>(_ state: StateType, action: @escaping (StateType) -> Disposable) -> Disposable {
    return self.scheduleInternal(state, action: action)
}
func scheduleInternal<StateType>(_ state: StateType, action: @escaping (StateType) -> Disposable) -> Disposable {
    return self.configuration.schedule(state, action: action)
}
/**
  Schedules an action to be executed.

  - parameter state: State passed to the action to be executed.
  - parameter dueTime: Relative time after which to execute the action.
  - parameter action: Action to be executed.
  - returns: The disposable object used to cancel the scheduled action (best effort).
  */
  public final func scheduleRelative<StateType>(_ state: StateType, dueTime: RxTimeInterval, action: @escaping (StateType) -> Disposable) -> Disposable {
      return self.configuration.scheduleRelative(state, dueTime: dueTime, action: action)
  }
/**
  Schedules a periodic piece of work.

  - parameter state: State passed to the action to be executed.
  - parameter startAfter: Period after which initial work should be run.
  - parameter period: Period for running the work periodically.
  - parameter action: Action to be executed.
  - returns: The disposable object used to cancel the scheduled action (best effort).
  */
  public func schedulePeriodic<StateType>(_ state: StateType, startAfter: RxTimeInterval, period: RxTimeInterval, action: @escaping (StateType) -> StateType) -> Disposable {
      return self.configuration.schedulePeriodic(state, startAfter: startAfter, period: period, action: action)
  }

分析以上方法会发现,最终都会调用 self.configuration 的某个方法。而且查看几种调度器的源码可以知道,Scheduler 中都有一个重要的属性 let configuration: DispatchQueueConfiguration。其中保存了我们需要的队列和leeway信息。

那么,我们就来分析 DispatchQueueConfiguration 中的方法。
在这里插入图片描述
首先分析 schedule 方法,虽然 schedule 方法中只有寥寥几句代码,但是也清晰的展示其 核心逻辑就是在当前队列下面,异步调度执行了闭包 action(state)

func scheduleRelative<StateType>(_ state: StateType, dueTime: Foundation.TimeInterval, action: @escaping (StateType) -> Disposable) -> Disposable {
    let deadline = DispatchTime.now() + dispatchInterval(dueTime)
    
    let compositeDisposable = CompositeDisposable()
    
    let timer = DispatchSource.makeTimerSource(queue: self.queue)
    timer.schedule(deadline: deadline, leeway: self.leeway)
    
    // 因篇幅原因,省略部分代码 ...
    timer.setEventHandler(handler: {
        if compositeDisposable.isDisposed {
            return
        }
        _ = compositeDisposable.insert(action(state))
        cancelTimer.dispose()
    })
    timer.resume()
    
    _ = compositeDisposable.insert(cancelTimer)
    
    return compositeDisposable
}
func schedulePeriodic<StateType>(_ state: StateType, startAfter: TimeInterval, period: TimeInterval, action: @escaping (StateType) -> StateType) -> Disposable {
    let initial = DispatchTime.now() + dispatchInterval(startAfter)
    
    var timerState = state
    
    let timer = DispatchSource.makeTimerSource(queue: self.queue)
    timer.schedule(deadline: initial, repeating: dispatchInterval(period), leeway: self.leeway)
    
    // 因篇幅原因,省略部分代码 ...
    timer.setEventHandler(handler: {
        if cancelTimer.isDisposed {
            return
        }
        timerState = action(timerState)
    })
    timer.resume()
    
    return cancelTimer
}

以上两个方法中虽然没有直接在当前队列中异步调用闭包,但是创建 timer 时,却是在当前队列中创建的,因此 timer 回调时也是在当前队列执行 eventHandler,间接实现当前队列下的调度。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

极客老师

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值