全网整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:400-708-3566

RxSwift学习教程之类型对象Subject详解

前言

在上一篇文章我们介绍了 Observable 的基本概念和使用情形。但是大多数情形下,我们需要在应用运行时添加数据到 Observable 中并将其发送给订阅者。在这种需求场景下,我们就不得不使用 RxSwift 中另一种类型对象了 - Subject 。

在应用中 Subject 实际上同时扮演了两个不同的角色:既是可观察对象同时也是观察者。这意味着 Subject 实例对象既可以接收事件也可以发送事件。例如,Subject 实例对象可以接收 next 事件信息,然后再将其发送给它自己的订阅者。示例代码:

let subject = PublishSubject<String>()

let subscriptionOne = subject
       .subscribe(onNext: { string in
        print(string)
       })

subject.on(.next("1"))

/* 打印结果:
1
*/

上面代码中使用的是 PublishSubject 类型的示例,而 RxSwift 中总共也四种类型的 Subject:

  • PublishSubject:初始化时并不包含数据,并且只会给订阅者发送后续数据。
  • BehaviorSubject:创建时需要包含初始数据,并且会给订阅者发送后续数据和最近的一次数据。
  • ReplaySubject:创建时需要指定对象缓存区容量,该容量表示会给订阅者重新发送订阅前数据的大小。
  • Variable:BehaviorSubject 对象的封装类型。它会将当前数据保存为状态并且只会给订阅者重新发送最近或者初始值。

下面将详细介绍这四种类型对象的概念以及它们的区别和使用情况。

PublishSubject

如果你仅仅是想让订阅者获取被观察者在生命周期内若产生的数据的话,那么你完全可以选用 PublishSubject 。而且 PublishSubject 对象的行为符合正常的预期,它只会给订阅者发送其订阅开始之后的数据。

例如,下图的最上面的时间线表示被观察者所发送的事件,而下面两个则分别代表不同的观察者。可以看到下面两个观察者都只会接收到订阅后所发送的事件而无法获知之前的情形。

对应的代码为:

let subject = PublishSubject<String>()

let subscriptionOne = subject
       .subscribe(onNext: { event in
        print("1) \( event.element ?? event)" )
       })

subject.on(.next("1")) 

let subscriptionTwo = subject
       .subscribe(onNext: { event in
        print("2) \(event.element ?? event)")
       })
 
subject.on(.next("2")) 

subject.on(.next("3")) 

/* 打印结果
1) 1
1) 2
2) 2
1) 3
2) 3
*/

如果此时我们取消 subscriptionOne 的订阅并发送新数据的话,那么结果为:

subscriptionOne.dispose()
subject.on(.next("4")) 

 /* 打印结果
 2) 4
 */

另外,当 PublishSubject 对象生命周期结束时,无论后续是否继续有数据产生该对象只会简单的发送之前结束生命周期的事件。

// 结束生命周期
subject.onCompleted()

// 发送新数据
subject.onNext("5")

// 结束观察
subscriptionTwo.dispose()

let disposeBag = DisposeBag()
// 重新进行订阅操作 
subject
 .subscribe { 
  print("3)", $0.element ?? $0) 
 } 
 .addDisposableTo(disposeBag)
// 发送新数据
subject.onNext("?")

/* 打印结果
2) completed
3) completed
 */

对于时序敏感的操作来说,PublishSubject 显然是非常合适的选择。但是并不是所有的情形都时序敏感,有时候我们可能会希望在订阅时能够获知最近一次的数据。此时,我们就需要使用 BehaviorSubject 对象了。

BehaviorSubject

BehaviorSubject 的行为与 PublishSubject 几乎一致,不过前者会给订阅者多发送一个最近的数据。图解如下:

图示中最上面对应的是所发射的数据,其中第二行表示第一个观察者,第三行则表示另一个。可以发现第一个观察者是在 1 之后 2 之前进行观察的,但是它依然能够获取到数据 1 。我们可以通过代码进行验证:

let subject = BehaviorSubject(value: "1")
let bag = DisposeBag()

subject
 .subscribe { event in
   print("1) event: \(event.element!) ")
 }
 .addDisposableTo(bag)

subject
 .subscribe { event in
  print("2) event: \(event.element!) ")
 }
 .addDisposableTo(bag)

subject.onNext("2")

subject
 .subscribe { event in
  print("3) event: \(event.element!) ")
 }
 .addDisposableTo(bag)

subject.onNext("3")

因为始终都能获取到最近的数据,所以对于那些可能需要默认值的场景,BehaviorSubject 显然是一个好的选择。

ReplaySubject

ReplaySubject 与 BehaviorSubject 的行为非常接近,只不过前者允许订阅者获取多于 1 个的最近数据。所以从某种意义上来说,后者是前者的一个特例。

下图就是一个 buffer 大小为 2 的 ReplaySubject 对象。它总过发射了三次数据,其中第一个观察者获取了所以的数据。而第二个观察者虽然是在第二个数据发射后才开始,但它依旧能获取缓存区中保存的数据。

代码表示如下:

let subject = ReplaySubject<String>.create(bufferSize: 2)

let bag = DisposeBag()

subject
 .subscribe { event in
  print("1) event: \(event.element!) ")
 }
 .addDisposableTo(bag)

subject.onNext("1")

subject.onNext("2")

subject
 .subscribe { event in
  print("2) event: \(event.element!) ")
 }
 .addDisposableTo(bag)

subject.onNext("3")

/* 打印结果:
1) event: 1 
1) event: 2 
2) event: 1 
2) event: 2 
1) event: 3 
2) event: 3 
*/

不过有一点值得我们注意,因为 ReplaySubject 缓存机制使用了数组结构,所以当有大量 ReplaySubject 对象时可能导致内存暴增。另外,如果缓存对象是图片等极耗内存的资源时也可能导致内存问题。所以 ReplaySubject 不可滥用且缓存区大小应该合理进行设置。

Variable

前面提到过 Variable 类型是 BehaviorSubject 的封装类型,从某种意义上你可以将前者当作后者的子类(实际上并不是)。Variable 类型实例的行为与 BehaviorSubject 一致,只不过前者添加了一些自有特性。你可以通过 value 属性访问和设置 Variable 类型实例当前的状态值,这意味着我们无需调用 onNext(_:) 了。

作为 BehaviorSubject 封装后的类型,Variable 在初始化时也需要设置默认值。另外,它发送数据的行为也与 BehaviorSubject 一致:只会给订阅者重新发送最近或者初始值。另一个独有的特性是,Variable 实例是不会触发 error 事件的。也就是说,你可以订阅 Variable 实例的错误事件,但是你并不能添加一个错误事件到实例中。

代码示例:

var variable = Variable("Initial value")

let bag = DisposeBag()

variable.value = "New initial value"

variable.asObservable()
 .subscribe { event in
  print("1) event: \(event.element!) ")
 }
 .addDisposableTo(bag)

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流,谢谢大家对的支持。


# rxswift  # rx  # subject  # 教程  # RxSwift实现替换delegate的方法示例  # 浅谈RxSwift 网络请求  # RxSwift使用技巧之过滤操作详解  # RxSwift学习之Observable的新建、订阅及取消订阅  # RxSwift学习教程之基础篇  # RxSwift发送及订阅 Subjects、Variables代码示例  # 会给  # 你可以  # 第一个  # 的是  # 是在  # 只会  # 第二个  # 默认值  # 自己的  # 时需  # 是一个  # 只不过  # 如果你  # 这意味着  # 子类  # 都能  # 将其  # 我们可以  # 意义上  # 在这种 


相关文章: 广州商城建站系统开发成本与周期如何控制?  音乐网站服务器如何优化API响应速度?  安云自助建站系统如何快速提升SEO排名?  Swift中switch语句区间和元组模式匹配  建站主机CVM配置优化、SEO策略与性能提升指南  如何自定义建站之星模板颜色并下载新样式?  黑客如何利用漏洞与弱口令入侵网站服务器?  教育培训网站制作流程,请问edu教育网站的域名怎么申请?  如何访问已购建站主机并解决登录问题?  常州企业网站制作公司,全国继续教育网怎么登录?  如何在搬瓦工VPS快速搭建网站?  一键网站制作软件,义乌购一件代发流程?  建站主机服务器选型指南与性能优化方案解析  网站制作价目表怎么做,珍爱网婚介费用多少?  怎么制作网站设计模板图片,有电商商品详情页面的免费模板素材网站推荐吗?  建站之星如何快速生成多端适配网站?  西安市网站制作公司,哪个相亲网站比较好?西安比较好的相亲网站?  韩国代理服务器如何选?解析IP设置技巧与跨境访问优化指南  建站之星安装后如何配置SEO及设计样式?  javascript中对象的定义、使用以及对象和原型链操作小结  非常酷的网站设计制作软件,酷培ai教育官方网站?  建站主机选哪家性价比最高?  jQuery 常见小例汇总  建站之星好吗?新手能否轻松上手建站?  建站之星北京办公室:智能建站系统与小程序生成方案解析  网站制作需要会哪些技术,建立一个网站要花费多少?  小建面朝正北,A点实际方位是否存在偏差?  韩国网站服务器搭建指南:VPS选购、域名解析与DNS配置推荐  网站制作报价单模板图片,小松挖机官方网站报价?  如何确保西部建站助手FTP传输的安全性?  建站为何优先选择香港服务器?  建站之星安装失败:服务器环境不兼容?  网站制作新手教程,新手建设一个网站需要注意些什么?  建站主机选择指南:服务器配置与SEO优化实战技巧  高端企业智能建站程序:SEO优化与响应式模板定制开发  如何用低价快速搭建高质量网站?  湖北网站制作公司有哪些,湖北清能集团官网?  如何生成腾讯云建站专用兑换码?  常州自助建站费用包含哪些项目?  制作充值网站的软件,做人力招聘为什么要自己交端口钱?  平台云上自主建站:模板化设计与智能工具打造高效网站  实例解析angularjs的filter过滤器  建站OpenVZ教程与优化策略:配置指南与性能提升  如何快速查询网址的建站时间与历史轨迹?  制作门户网站的参考文献在哪,小说网站怎么建立?  如何选择建站程序?包含哪些必备功能与类型?  如何在香港服务器上快速搭建免备案网站?  建站之星下载版如何获取与安装?  如何通过.red域名打造高辨识度品牌网站?  定制建站模板如何实现SEO优化与智能系统配置?18字教程 

您的项目需求

*请认真填写需求信息,我们会在24小时内与您取得联系。