七、Subjects 介绍
- 从前面的几篇文章可以发现,当我们创建一个
Observable的时候就要预先将要发出的数据都准备好,等到有人订阅它时再将数据通过Event发出去。- 但有时我们希望
Observable在运行时能动态地“获得”或者说“产生”出一个新的数据,再通过Event发送出去。比如:订阅一个输入框的输入内容,当用户每输入一个字后,这个输入框关联的Observable就会发出一个带有输入内容的Event,通知给所有订阅者。- 这个就可以使用下面将要介绍的
Subjects来实现。
1,Subjects 基本介绍
(1)Subjects 既是订阅者,也是 Observable:
- 说它是订阅者,是因为它能够动态地接收新的值。
- 说它又是一个
Observable,是因为当Subjects有了新的值之后,就会通过Event将新值发出给他的所有订阅者。
(2)一共有四种 Subjects,分别为:PublishSubject、BehaviorSubject、ReplaySubject、Variable。他们之间既有各自的特点,也有相同之处:
- 首先他们都是
Observable,他们的订阅者都能收到他们发出的新的Event。 - 直到
Subject发出.complete或者.error的Event后,该Subject便终结了,同时它也就不会再发出.next事件。 - 对于那些在
Subject终结后再订阅他的订阅者,也能收到subject发出的一条.complete或.error的event,告诉这个新的订阅者它已经终结了。 - 他们之间最大的区别只是在于:当一个新的订阅者刚订阅它的时候,能不能收到
Subject以前发出过的旧Event,如果能的话又能收到多少个。
(3)Subject 常用的几个方法:
-
onNext(:):是
on(.next(:))的简便写法。该方法相当于subject接收到一个.next事件。 -
onError(:):是
on(.error(:))的简便写法。该方法相当于subject接收到一个.error事件。 -
onCompleted():是
on(.completed)的简便写法。该方法相当于subject接收到一个.completed事件。
2,PublishSubject
(1)基本介绍
-
PublishSubject是最普通的Subject,它不需要初始值就能创建。 -
PublishSubject的订阅者从他们开始订阅的时间点起,可以收到订阅后Subject发出的新Event,而不会收到他们在订阅前已发出的Event。
(2)时序图
- 最上面一条是
PublishSubject。 - 下面两条分别表示两个新的订阅,它们订阅的时间点不同,可以发现
PublishSubject的订阅者只能收到他们订阅后的Event。
(3)使用样例
let disposeBag = DisposeBag()
//创建一个PublishSubject
let subject = PublishSubject<String>()
//由于当前没有任何订阅者,所以这条信息不会输出到控制台
subject.onNext("111")
//第1次订阅subject
subject.subscribe(onNext: { string in
print("第1次订阅:", string)
}, onCompleted:{
print("第1次订阅:onCompleted")
}).disposed(by: disposeBag)
//当前有1个订阅,则该信息会输出到控制台
subject.onNext("222")
//第2次订阅subject
subject.subscribe(onNext: { string in
print("第2次订阅:", string)
}, onCompleted:{
print("第2次订阅:onCompleted")
}).disposed(by: disposeBag)
//当前有2个订阅,则该信息会输出到控制台
subject.onNext("333")
//让subject结束
subject.onCompleted()
//subject完成后会发出.next事件了。
subject.onNext("444")
//subject完成后它的所有订阅(包括结束后的订阅),都能收到subject的.completed事件,
subject.subscribe(onNext: { string in
print("第3次订阅:", string)
}, onCompleted:{
print("第3次订阅:onCompleted")
}).disposed(by: disposeBag)
运行结果如下:
3,BehaviorSubject
(1)基本介绍
-
BehaviorSubject需要通过一个默认初始值来创建。 - 当一个订阅者来订阅它的时候,这个订阅者会立即收到
BehaviorSubjects上一个发出的event。之后就跟正常的情况一样,它也会接收到BehaviorSubject之后发出的新的event。
(2)时序图
- 最上面一条是
BehaviorSubject。 - 下面两条分别表示两个新的订阅,它们订阅的时间点不同,可以发现
BehaviorSubject的订阅者一开始就能收到BehaviorSubjects之前发出的一个Event。
]
(3)使用样例
let disposeBag = DisposeBag()
//创建一个BehaviorSubject
let subject = BehaviorSubject(value: "111")
//第1次订阅subject
subject.subscribe { event in
print("第1次订阅:", event)
}.disposed(by: disposeBag)
//发送next事件
subject.onNext("222")
//发送error事件
subject.onError(NSError(domain: "local", code: 0, userInfo: nil))
//第2次订阅subject
subject.subscribe { event in
print("第2次订阅:", event)
}.disposed(by: disposeBag)
运行结果如下:
4,ReplaySubject
(1)基本介绍
-
ReplaySubject在创建时候需要设置一个bufferSize,表示它对于它发送过的event的缓存个数。 - 比如一个
ReplaySubject的bufferSize设置为 2,它发出了 3 个.next的event,那么它会将后两个(最近的两个)event给缓存起来。此时如果有一个subscriber订阅了这个ReplaySubject,那么这个subscriber就会立即收到前面缓存的两个.next的event。 - 如果一个
subscriber订阅已经结束的ReplaySubject,除了会收到缓存的.next的event外,还会收到那个终结的.error或者.complete的event。
(2)时序图
- 最上面一条是
ReplaySubject(bufferSize设为为 2)。 - 下面两条分别表示两个新的订阅,它们订阅的时间点不同。可以发现
ReplaySubject的订阅者一开始就能收到ReplaySubject之前发出的两个Event(如果有的话)。
(3)使用样例
let disposeBag = DisposeBag()
//创建一个bufferSize为2的ReplaySubject
let subject = ReplaySubject<String>.create(bufferSize: 2)
//连续发送3个next事件
subject.onNext("111")
subject.onNext("222")
subject.onNext("333")
//第1次订阅subject
subject.subscribe { event in
print("第1次订阅:", event)
}.disposed(by: disposeBag)
//再发送1个next事件
subject.onNext("444")
//第2次订阅subject
subject.subscribe { event in
print("第2次订阅:", event)
}.disposed(by: disposeBag)
//让subject结束
subject.onCompleted()
//第3次订阅subject
subject.subscribe { event in
print("第3次订阅:", event)
}.disposed(by: disposeBag)
运行结果如下:
5,Variable
(1)基本介绍
-
Variable其实就是对BehaviorSubject的封装,所以它也必须要通过一个默认的初始值进行创建。 -
Variable具有BehaviorSubject的功能,能够向它的订阅者发出上一个event以及之后新创建的event。 - 不同的是,
Variable还会把当前发出的值保存为自己的状态。同时它会在销毁时自动发送.complete的event,不需要也不能手动给Variables发送completed或者error事件来结束它。 - 简单地说就是
Variable有一个value属性,我们改变这个value属性的值就相当于调用一般Subjects的onNext()方法,而这个最新的onNext()的值就被保存在value属性里了,直到我们再次修改它。
注意:
Variables本身没有subscribe()方法,但是所有Subjects都有一个asObservable()方法。我们可以使用这个方法返回这个Variable的Observable类型,拿到这个Observable类型我们就能订阅它了。
(2)使用样例
import UIKit
import RxSwift
import RxCocoa
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let disposeBag = DisposeBag()
//创建一个初始值为111的Variable
let variable = Variable("111")
//修改value值
variable.value = "222"
//第1次订阅
variable.asObservable().subscribe {
print("第1次订阅:", $0)
}.disposed(by: disposeBag)
//修改value值
variable.value = "333"
//第2次订阅
variable.asObservable().subscribe {
print("第2次订阅:", $0)
}.disposed(by: disposeBag)
//修改value值
variable.value = "444"
}
}
运行结果如下:
注意:由于
Variable对象在viewDidLoad()方法内初始化,所以它的生命周期就被限制在该方法内。当这个方法执行完毕后,这个Variable对象就会被销毁,同时它也就自动地向它的所有订阅者发出.completed事件









网友评论