RxSwift介绍(三)——更加灵活的Subject
时间:2022-06-19
本文章向大家介绍RxSwift介绍(三)——更加灵活的Subject,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
前一篇文章讲述 RxSwift 框架中最重要的类 Observable<T>
,但是其局限性只能作为被订阅者被动接收信号并响应事件。项目中避免不了主动发出信号操作的情况,这时就需要 Subject
类来完成。与之前RAC框架中的 Subject 类功能非常相似,既能攻也能受,是不仅可以成为可观察对象被动接受事件,还可以成为观察者主动发送事件。
Subject 其订阅者也是 Observable
,首先可以动态地接受新值,其次当 subject 值更新时,会通过 event 把新值发送给所有的订阅者。
在 RxSwift 框架中,提供了四种类型的 subject,首先要了解的一点就是提供的四种 subject 创建方式最主要的区别:当一个新的订阅者订阅到subject对象时,能否收到 subject 以前发出过的旧 event,如果能,接收的数量又有不同。
-
PublishSubject
最普通的 subject ,不需要初始值就可以创建,而且从订阅者开始订阅的时间点起,可以收到 subject 发出的新 event,而不会收到在订阅前已发出的 event -
BehaviorSubject
当订阅者订阅 subject 时,会立即收到 BehaviorSubject 上一个发出的 event,之后与 PublishSubject 功能相同 -
ReplaySubject
除了包含 PublishSubject 的功能,还可以手动设置订阅者接收到旧的 event 个数。因此,在使用时必须在创建时设置 bufferSize,表示将会返回给订阅者对应个数最近缓存的旧 event (注:若一个订阅者去订阅已经结束的 ReplaySubject ,除了会收到缓存的 .next 的 event之外,还会收到终结该 ReplaySubject 的 .error 或 .completed 的event) 在实际开发过程中,ReplaySubject 缓存机制使用了数组结构
,所以当有大量 ReplaySubject 对象时可能导致内存暴增。另外,如果缓存对象是图片、视频等极耗内存的资源时也可能导致内存问题。所以 ReplaySubject 不可滥用且缓存区大小必须合理进行设置,必要时可手动进行释放管理 -
Variable
本身是对 BehaviorSubject 封装,创建时也必须设置一个默认值。继承自 BehaviorSubject ,那么就能向订阅者发出上一个 event 与新的 event。与 BehaviorSubject 不同的是,Variable还会把当前发出的值保存为自己的状态,同时在销毁时自动发送 .completed event,不需要也不能手动给 Variable 发送终结事件 .completed 或 .error 来终结。 换个方式理解,Variable 有一个 value 属性,当改变 value 属性的值时就相当于调用一般 Subjects 的 onNext() 方法,而这个最新的 onNext() 的值就被保存在 value 属性里,直到再次修改 value (注:Variable 本身没有提供 subscribe() 方法,但是所有 Subjects 都有一个 asObservable() 方法。可以使用这个方法返回这个 Variable 的 Observable 类型,拿到这个 Observable 类型就能订阅它了)
介绍了以上四种 subject ,接下来贴代码并附上运行打印截图,有兴趣的可以copy下来运行一遍,了解其 event 执行顺序
PublishSubject代码示例
let subject = PublishSubject<String>()
subject.onNext("first signal")
subject.subscribe(onNext: { (event) in
print("first event is"+event)
}, onCompleted: {
print("completed first")
}) {
print("first :销毁了")
}.disposed(by: disposeB)
subject.onNext("second signal")
subject.subscribe(onNext: { (event) in
print("second event is "+event)
}, onCompleted: {
print("completed second")
}) {
print("second :销毁了")
}.disposed(by: disposeB)
//让subject结束,后面再进行订阅
subject.onCompleted()
subject.onNext("third signal")
subject.onNext("fourth signal")
subject.subscribe(onNext: { (event) in
print("this is another"+event)
}, onCompleted: {
print("completed another")
}) {
print("another :销毁了")
}.disposed(by: disposeB)
PublishSubject打印结果
BehaviorSubject代码示例
let subject = BehaviorSubject(value: "first signal")
subject.onNext("another first signal") //会替换了 first signal 的信号
subject.subscribe(onNext: { (event) in
print(event)
} , onCompleted: {
print("completed")
}) {
print("第一个销毁了")
}.disposed(by: disposeB)
subject.onNext("second signal")
subject.onNext("third signal") //这里试图替换上面的 second signal 的event
subject.subscribe(onNext: { (event) in
print(event)
} , onCompleted: {
print("completed")
}) {
print("第二个销毁了")
}.disposed(by: disposeB)
subject.onError(NSError(domain: "myError", code: 10010, userInfo: ["myUserInfo":"10010错误"]))
BehaviorSubject打印结果
ReplaySubject代码示例
//设置缓存最近2个event
let subject = ReplaySubject<String>.create(bufferSize: 2)
subject.onNext("first")
subject.onNext("second")
subject.onNext("third")
subject.subscribe(onNext: { (event) in
print(event)
}, onError: { (error) in
print(error)
}, onCompleted: {
print("这是一个 完成")
}) {
print("销毁了")
}.disposed(by: disposeB)
subject.onCompleted()//现在终结subject
subject.subscribe(onNext: { (event) in
print(event)
}, onError: { (error) in
print(error)
}, onCompleted: {
print("完成之后的订阅完成")
}) {
print("完成之后销毁了")
}.disposed(by: disposeB)
ReplaySubject打印结果
Variable代码示例
let subject = Variable("first")
subject.value = "second"
subject.asObservable().subscribe(onNext: { (event) in
print(event)
}, onError: { (error) in
print(error)
}, onCompleted: {
print("Variber订阅完成")
}) {
print("Variber销毁")
}
.disposed(by: disposeB)
subject.value = "third"
Variable打印结果
打印结果中给出了一个警告,在其GitHub的issue链接中,提到了 Variable 要在接下来的版本里删除,请用 BehaviorRelay 代替,其实 Variable 封装,还是比较顺手。貌似现在UI层的很多都是 Variable 来管理,但 RxSwift 也封装了很多关于UI的,issue的回复中说以后会销毁,注意是销毁 Variable 这个类。
- Java-单例模式详解(图文并茂,简单易懂)
- Fragment生命周期及实现点击导航图片切换fragment,Demo
- 《GO IN ACTION》读后记录:GO的并发与并行
- SharedPreferences 存List集合,模拟数据库,随时存取
- Servlet与Jsp的结合使用实现信息管理系统一
- Mac下nvm管理node.js版本问题
- 自定义tab吸顶效果一(原理)
- OpenGL ES学习001---绘制三角形
- Android之MaterialDesign应用技术2-仿支付宝上滑搜索框缓慢消失
- 披着狼皮的羊——寻找惠普多款打印机中的RCE漏洞
- Android之MaterialDesign应用技术
- 蛙啊!老母亲给你整理了DEDECMS漏洞集合,快回家!
- Android之Bmob移动后端云服务器
- golang基于redis lua封装的优先级去重队列
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 如何定位 golang 进程 hang 死的 bug
- Docker/Dockerfile debug调试技巧
- 使用 HTTP/2 提升性能的几个建议
- 玩树莓派(raspberry pi) 2/3 raspbian的遇到的一些问题
- Dnsmasq加速本地DNS请求
- swoole深入学习 2. tcp Server和tcp Client
- 一切皆Socket
- Go代码重构:23倍的性能爆增
- 分布式系统的一致性协议之 2PC 和 3PC
- Docker快速搭建WordPress博客网站
- Elasticsearch入门,这一篇就够了
- 玩转 lua in Redis
- 用docker快速搭建wordpress博客
- 生产环境优雅的重启基于Nginx、Tornado的Web服务进程
- nginx记录post body/payload数据 日志用打印出结果