六、Subject

来看一个非常特殊的类型-Subject,为什么说它特殊呢?原因很简单:**Subject既可以做序列,也可以做观察者!**正是因为这一特性,所以在实际开发中被大量运用。下面我们一起来解读一下这个特殊的Subject

6.1 基本原理

首先我们来看看:SubjectType的原理!

public protocol SubjectType : ObservableType {// 关联了观察者类型,具备这个类型的能力associatedtype SubjectObserverType : ObserverTypefunc asObserver() -> SubjectObserverType
}
  • SubjectType首先就是继承了ObservableType,具有序列特性
  • 关联了观察者类型,具备这个类型的能力
  • 下面我们通过一个具体类型来感受一下`subject
  • 很明显能够订阅信号(序列最基本的能力)
  • 能够发送响应,又是观察者的能力
  • 查看底层源码分析

6.1.1 订阅响应流程

  • self._observers.insert(observer.on): 通过一个集合添加进去所有的订阅事件,很明显在合适的地方一次性全部执行
  • 其中也返回这次订阅的销毁者,方便执行善后工作: synchronizedUnsubscribe->self._observers.removeKey(disposeKey)
  • 便利通过key获取响应bag中的value,执行集合移除
  • 因为没有相应持有关系,达到自动释放销毁

6.1.2 发送信号流程

  • 这个地方估计大家看起来麻烦恶心一点,但是你用心看不难体会
  • 这里主要调用了dispatch函数,传了两个参数:self._synchronized_on(event)event
  • 查看dispatch函数源码
  • bag._value0?(event)首先执行事件的回调
  • 判断bag._onlyFastPath的情况,默认会开启快速通道!
  • 如果是开启慢速通道,需要从刚刚添加进bag包裹里面的匹配对挨个进行pairs[i].value(event),外界事件回调,然后拿回外界封装的闭包的闭包调用:element(event)

  • 这里如果self._isDisposed || self._stopped成立就会返回一个空的集合,也就没有序列的响应
  • .completed, .error都会改变状态self._stopped = true,也就是说序列完成或者错误之后都无法再次响应了
  • .completed, .error还会移除添加在集合里面的内容

其实如果你对前面序列的流程掌握了,这个subject的流程也不再话下,只是subject 把订阅流程和响应流程都内部实现,所以也就没有必要引入sink

6.2 各种Subject

6.2.1 PublishSubject

可以不需要初始来进行初始化(也就是可以为空),并且它只会向订阅者发送在订阅之后才接收到的元素。

// PublishSubject
// 1:初始化序列
let publishSub = PublishSubject<Int>() //初始化一个PublishSubject 装着Int类型的序列
// 2:发送响应序列
publishSub.onNext(1)
// 3:订阅序列
publishSub.subscribe { print("订阅到了:",$0)}.disposed(by: disposbag)
// 再次发送响应
publishSub.onNext(2)
publishSub.onNext(3)
/*
订阅到了: next(2)
订阅到了: next(3)
*/
  • 信号:1是无法被订阅的,只接受订阅之后的响应

6.2.2 BehaviorSubject

通过一个默认初始值来创建,当订阅者订阅BehaviorSubject时,会收到订阅后Subject上一个发出的Event,如果还没有收到任何数据,会发出一个默认值。之后就和PublishSubject一样,正常接收新的事件。

PublishSubject 稍微不同就是BehaviorSubject这个家伙有个存储功能:存储上一次的信号

print("**********BehaviorSubject**********")
// BehaviorSubject
// 1:创建序列
let behaviorSub = BehaviorSubject.init(value: 100)
// 2:发送信号
behaviorSub.onNext(2)
behaviorSub.onNext(3)
// 3:订阅序列
behaviorSub.subscribe{ print("订阅到了:",$0)}.disposed(by: disposbag)
// 再次发送
behaviorSub.onNext(4)
behaviorSub.onNext(5)
// 再次订阅
behaviorSub.subscribe{ print("订阅到了:",$0)}.disposed(by: disposbag)
/*
**********BehaviorSubject**********
订阅到了: next(3)
订阅到了: next(4)
订阅到了: next(5)
订阅到了: next(5)
*/
  • 当没有信号的时候,会默认发送 信号:100
  • 只能储存一个信号:信号2 会被 信号3 覆盖
  • 订阅信号之前能够储存信号
  • 初始化的时候带有一个属性保存一个信号
  • 事件响应:新事件会覆盖原来的事件
  • 其他流程和publish一样

6.2.3 ReplaySubject

ReplaySubject 发送源Observable 的所有事件无论observer什么时候开始订阅。

print("**********ReplaySubject**********")
// ReplaySubject
// 1:创建序列
let replaySub = ReplaySubject<Int>.create(bufferSize: 2)
// let replaySub = ReplaySubject<Int>.createUnbounded()// 2:发送信号
replaySub.onNext(1)
replaySub.onNext(2)
replaySub.onNext(3)
replaySub.onNext(4)// 3:订阅序列
replaySub.subscribe{ print("订阅到了:",$0)}.disposed(by: disposbag)
// 再次发送
replaySub.onNext(7)
replaySub.onNext(8)
replaySub.onNext(9)/*
**********ReplaySubject**********
订阅到了: next(3)
订阅到了: next(4)
订阅到了: next(7)
订阅到了: next(8)
订阅到了: next(9)*/
  • 一个bufferSize空间,想存储多少次响应就是多少次

    — 调用 addValueToBuffer 函数将发送的元素加入到 queue 中。

    — 调用 trim 函数删除 queue 中大于 bufferSize 的多余的元素。

  • 其他流程照旧

  • 源码里面就是相对于BehaviorSubject的储存属性变成了集合

6.2.4 AsyncSubject

AsyncSubject只发送由源Observable发送的最后一个事件,并且只在源Observable完成之后。(如果源Observable没有发送任何值,AsyncSubject也不会发送任何值。)

print("**********AsyncSubject**********")
// AsyncSubject
// 1:创建序列
let asynSub = AsyncSubject<Int>.init()
// 2:发送信号
asynSub.onNext(1)
asynSub.onNext(2)
// 3:订阅序列
asynSub.subscribe{ print("订阅到了:",$0)}.disposed(by: disposbag)
// 再次发送
asynSub.onNext(3)
asynSub.onNext(4)
asynSub.onError(NSError.init(domain: "pxwx", code: 10086, userInfo: nil))
asynSub.onCompleted()
/*
**********AsyncSubject**********
订阅到了: error(Error Domain=pxwx Code=10086 "(null)")
*/

6.2.5 Variable

Variable废弃了,这里贴出代码以供大家遇到老版本! 由于这个Variable的灵活性所以在开发里面应用非常之多!

print("**********Variable**********")
// Variable : 5.0已经废弃(BehaviorSubject 替换) - 这里板书 大家可以了解一下
// 1:创建序列
let variableSub = Variable.init(1)
// 2:发送信号
variableSub.value = 100
variableSub.value = 10
// 3:订阅信号
variableSub.asObservable().subscribe{ print("订阅到了:",$0)}.disposed(by: disposbag)
// 再次发送
variableSub.value = 1000
/*
**********Variable**********
订阅到了: next(10)
订阅到了: next(1000)
*/

6.2.6 BehaviorRelay

  • 替换原来的Variable
  • 可以储存一个信号
  • 随时订阅响应
  • 响应发送的时候要注意:behaviorR.accept(20)
print("**********BehaviorRelay**********")
let behaviorRelay = BehaviorRelay(value: 100)
behaviorRelay.subscribe(onNext: { (num) inprint("订阅到了:\(num)")
}).disposed(by: disposbag)
behaviorRelay.accept(1000)
/*
**********BehaviorRelay**********
订阅到了:100
订阅到了:1000
订阅到了: completed
*/

RxSwift序列—Subject相关推荐

  1. 【RxSwift】flatMapLatest、 Error事件中断序列

    RxSwift序列转换 map 将序列每个元素转换一遍,适合于序列内的元素类型改变,比如Bool转换为String, 或者其他值的操作. 输入类型, 输出还是类型 flapMap 将序列的元素转换为其 ...

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

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

  3. 响应式编程知多少 | Rx.NET 了解下

    1. 引言 An API for asynchronous programming with observable streams. ReactiveX is a combination of the ...

  4. blast java_Blast在windows下的使用过程

    2.1在c盘下建立三个包 移动到blast有bin的包下,输入blastn -version来看是否安装成功 2.2创建db 这个最后一个出问题了,它提示我File nr does not exist ...

  5. 本地blast~TBtools

    首先,需要准备两个文件.第一个是建库(近缘物种目标基因),类似于这种格式:第二个是自己物种的protein.fasta 打开TBtools,选择blast→several sequences to a ...

  6. 关于.NET RX学习资料

    参考资料: https://github.com/haoljp/Rx.NET/tree/develop/Rx.NET/Samples 一些简单实例 https://github.com/haoljp/ ...

  7. 数据格式_初识生信常见数据格式知多少?

    ?点击上方蓝字把我们设为星标吧✴ 前言 刚刚踏入生信圈的你,有没有因为各种数据格式而困惑过?比如基因组Fasta序列,又或者二代测序的Fastq数据.这些数据有哪些特点?又有哪些日常操作是生信小白必须 ...

  8. RxSwift之深入解析Subject的使用和实现原理

    一.Subject RxSwift 的核心逻辑 Observable 不具备发送事件的能力,创建一个 Observable 的时候就要预先将要发出的数据都准备好,等到有人订阅它时再将数据通过 Even ...

  9. RxSwift之深入解析特殊序列deallocating与deallocated的源码实现

    一.引言 在 RxSwfit 中,有两个特殊序列:deallocating 与 deallocated,deinit 等价于 dealloc.在 deallocating 与 deallocated ...

最新文章

  1. 获取checkbox所选中的值
  2. Android开发学习笔记:Gallery和GridView浅析
  3. NLP:对字符串按照一个、多个自定义分隔符进行分割、将列表转为字符串同时自定义连接符
  4. [部署]VM11下CentOS7mini安装及配置
  5. 体验cas server
  6. 如何把a1的图纸变成a0_如何安装家用空开配电
  7. 介绍一个修改 Visual Studio Code 侧边框颜色的扩展 Peacock
  8. BZOJ.2738.矩阵乘法(整体二分 二维树状数组)
  9. typescript get方法_.NET手撸绘制TypeScript类图——上篇
  10. MySQL在Windows和Linux减少数据库
  11. 动态创建表格(各种管理系统常见)
  12. 基于层序+中序遍历序列构建二叉树
  13. linux pxe dhcp 讲解,RHEL 5 PXE+DHCP+NFS+SFTP无人职守网络安装配置
  14. 车辆十四自由度动力学建模分析
  15. pr.exe、Churrasco.exe、ms10048.exe用法及提权原理 上帝模式
  16. PS制作光束散射的旋转文字效果
  17. 内存核心频率、工作频率,等效频率、预读取技术详解
  18. 电脑硬盘空间如何免费扩容2TB+
  19. 加州大学圣地亚哥计算机硕士申请,多次催促 成功申请加州大学圣地亚哥分校计算机科学...
  20. 正则表达式匹配居民身份证

热门文章

  1. android 存储盘 dcim,DCIM是个啥?安卓图片存储位置指南
  2. 华为智慧森林防火监测预警解决方案
  3. 常用的MATLAB网络资源
  4. BBR原版/魔改/plus/锐速/七合一脚本linux加速脚本/硬盘挂载/cc防御/宝塔
  5. VS2017+VUE创建项目爬坑
  6. 软件工程导论--设计工程
  7. 项目经验之:针对昨日FDO连接SDF文件报错,国外GIS论坛给出了一个思路.帮助我过关.
  8. Ninja安装和基本使用
  9. 互联网,因特网和万维网的区别是什么?
  10. 计算机科学——计算机导论