服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - Swift - RxSwift学习教程之类型对象Subject详解

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

2021-01-07 15:34BigNerdCoding Swift

这篇文章主要给大家介绍了关于RxSwift学习教程之类型对象Subject的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起看看吧。

前言

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

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

?
1
2
3
4
5
6
7
8
9
10
11
12
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 对象的行为符合正常的预期,它只会给订阅者发送其订阅开始之后的数据。

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

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

对应的代码为:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
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 的订阅并发送新数据的话,那么结果为:

?
1
2
3
4
5
6
subscriptionOne.dispose()
subject.on(.next("4"))
 
 /* 打印结果
 2) 4
 */

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// 结束生命周期
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 几乎一致,不过前者会给订阅者多发送一个最近的数据。图解如下:

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

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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 对象。它总过发射了三次数据,其中第一个观察者获取了所以的数据。而第二个观察者虽然是在第二个数据发射后才开始,但它依旧能获取缓存区中保存的数据。

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

代码表示如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
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 实例的错误事件,但是你并不能添加一个错误事件到实例中。

代码示例:

?
1
2
3
4
5
6
7
8
9
10
11
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)

总结

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

原文链接:https://bignerdcoding.com/archives/52.html

延伸 · 阅读

精彩推荐
  • Swift浅谈在Swift中关于函数指针的实现

    浅谈在Swift中关于函数指针的实现

    这篇文章主要介绍了浅谈在Swift中关于函数指针的实现,是作者根据C语言的指针特性在Swifft中做出的一个实验,需要的朋友可以参考下...

    Swift教程网4372020-12-21
  • SwiftSwift中排序算法的简单取舍详解

    Swift中排序算法的简单取舍详解

    对于排序算法, 通常简单的, 为大家所熟知的有, 选择排序, 冒泡排序, 快速排序, 当然还有哈希, 桶排序之类的, 本文仅比较最为常见的选择, 冒泡和快排,文...

    Castie111012021-01-10
  • SwiftSwift网络请求库Alamofire使用详解

    Swift网络请求库Alamofire使用详解

    这篇文章主要为大家详细介绍了Swift网络请求库Alamofire的使用方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    lv灬陈强56682021-01-06
  • Swift分析Swift性能高效的原因

    分析Swift性能高效的原因

    绝大多数公司选择Swift语言开发iOS应用,主要原因是因为Swift相比Objc有更快的运行效率,更加安全的类型检测,更多现代语言的特性提升开发效率;这一系...

    louis_wang9092021-01-16
  • Swift详解Swift 之clipped是什么如何用

    详解Swift 之clipped是什么如何用

    这篇文章主要介绍了详解Swift 之clipped是什么如何用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下...

    iCloudEnd8532021-05-28
  • Swiftswift相册相机的权限处理示例详解

    swift相册相机的权限处理示例详解

    在iOS7以后要打开手机摄像头或者相册的话都需要权限,在iOS9中更是更新了相册相关api的调用,那么下面这篇文章主要给大家介绍了关于swift相册相机权限处...

    hello老文12682021-01-08
  • SwiftSwift算法之栈和队列的实现方法示例

    Swift算法之栈和队列的实现方法示例

    Swift语言中没有内设的栈和队列,很多扩展库中使用Generic Type来实现栈或是队列。下面这篇文章就来给大家详细介绍了Swift算法之栈和队列的实现方法,需要...

    李峰峰10002021-01-05
  • SwiftSwift 基本数据类型详解总结

    Swift 基本数据类型详解总结

    在我们使用任何程序语言编程时,需要使用各种数据类型来存储不同的信息。变量的数据类型决定了如何将代表这些值的位存储到计算机的内存中。在声明...

    Lucky_William4672021-12-26