四、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 = statelet 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,间接实现当前队列下的调度。

RxSwift系列—RxSwift调度者相关推荐

  1. RxSwift系列—RxSwift高阶函数

    3.1 组合操作符 3.1.1 startWith 在开始从可观察源发出元素之前,发出指定的元素序列 print("*****startWith*****") Observable ...

  2. RxSwift 系列(一)

    为什么使用RxSwift? 我们编写的代码绝大多数都涉及对外部事件的响应.当用户点击操作时,我们需要编写一个@IBAction事件来响应.我们需要观察通知,以检测键盘何时改变位置.当网络请求响应数据时 ...

  3. RxSwift系列—Driver

    五.Driver 5.1 案例引入 请求一次网络,绑定到UI上 5.1.1 采用Observerable let result0 = inputTF.rx.text.skip(1).flatMap { ...

  4. linux多核编程系列之调度亲和性,关于CPU亲和性,这篇讲得最全面

    何为CPU的亲和性 CPU的亲和性,进程要在某个给定的 CPU 上尽量长时间地运行而不被迁移到其他处理器的倾向性,进程迁移的频率小就意味着产生的负载小.亲和性一词是从affinity翻译来的,实际可以 ...

  5. jenkin系列_调度jmeter实现分布式测试

    假设现在有 192.168.1.100(jmeter 控制器 C ).192.168.1.101(jmeter负载机 B)两台机器进行分布式测试,各个步骤如下 1. C 和B 安装jmeter,并运行 ...

  6. 干货集中营 ReactiveCocoa+RXSwift+MVVM

    原文地址: 传送门简书只做同步更新功能 学习函数响应式编程已经接近两个月的时间.说实话坚持下来实在不易.两个月的时间看过近150篇博文,算下来啃下来一本千页的技术书籍也差不多.不过随着知识面的拓广,学 ...

  7. Rxswift学习之(一)函数响应式编程思想

    Rxswift学习之(一)函数响应式编程思想 1. 函数响应式编程思想必备基本概念简介 2. iOS中三种编程思想:链式.函数式和响应式编程 2.1 链式编程 2.2 函数式编程 2.3 响应式编程 ...

  8. RxSwift技术路线与参考资料

    RxSwift技术路线与参考资料 ## RxSwift简介 响应式编程 响应式编程(Reactive Programming)是一种通过异步和数据流来构建事务关系的编程思想.核心体现就是观察者和可被观 ...

  9. RxSwift使用教程

    前言 欢迎Follow我的Github,博客会同步在Github的Blog仓库更新. Github地址: LeoMobileDeveloper RxSwift是Swift函数响应式编程的一个开源库,由 ...

最新文章

  1. TDD in .NET Core - 简介
  2. 何杰月c语言课程,北京西城区教育科研月:学科核心素养的教学探索
  3. MongoDB数据库备份与恢复
  4. hdu 4143 A Simple Problem 数论
  5. c语言中的jsonpath的处理
  6. UE4如何贴混合贴图_UE4[蓝图]动态积雪材质的实现(一)
  7. 网速提高学习周——系统篇
  8. re.compile
  9. 红石32位cpu通用计算机,我的世界无命令方块32位红石电脑装置详解
  10. 单片机移频防啸叫_基于ARM9的防啸叫音频放大器的设计
  11. xShell终端中文乱码完全解决方法
  12. 需求处理的三个步骤:需求梳理、需求分析、需求放大
  13. Python Numpy
  14. 树莓派chromium浏览器 kiosk 全屏提示错误
  15. 【IoT】产品设计之思维模型:四种知识结构
  16. 嘉应大学黄林鑫计算机学院,林鑫-中国科学院大学-UCAS
  17. 软件性能测试的几种方法
  18. 读书笔记 - 《基业长青》
  19. A*寻路算法python版(第二版)
  20. 120M硬盘的jslinux

热门文章

  1. fiddler设置字体
  2. 美通企业日报 | 阿迪达斯和碧昂丝达成标志性合作;万豪国际公布亚太区2020年发展愿景...
  3. linux 搭建Discuz论坛教程-个人实践笔记
  4. 字节码增强技术 Byte Buddy 、Javassist、Instrumentation
  5. KindEditor在线文本编辑器
  6. jenkins 创建用户角色项目权限
  7. (转)周鸿祎产品秘笈:小版本成就大产品
  8. 【统计学的学习方法论】
  9. CommandName属性和CommandArgument属性[转]
  10. MATLAB之function函数