Subjects
创建 Observable 序列之后, 要预先将要发出的数据准备好, 等到有人订阅时, 再将数据通过 Event 发出去.
我们希望 Observable 序列能在运行时动态的 获得 或者说 产生 一个新数据, 再通过 Event 发送出去. 比如: 订阅一个输入框的输入内容, 当用户每输入一个字后, 这个输入框关联的 Observable 就会发出一个带有输入内容的 Event, 通知给所有的订阅者. 这个就可以使用 Subjects 来实现.
Subjects 基本介绍
(1) Subjects 它是订阅者, 也是 Obervable :
- 它是订阅者, 因为它能够动态的接收新的值
- 它是一个
Observable, 是因为当Subjects有了新的值之后, 就会通过Event将新值发出给他的所有订阅者.
(2) 一共有四种 Subjects, 分别是 PublishSubject、BehaviorSubject、ReplaySubject 、 Variable(已废弃) 和 BehaviorRelay(Variable替代品).
- 它们都是
Observable, 它们的订阅者都能收到它们发出的Event - 直到
Subject发出.complete或者.error的Event之后, 该Subject才会终结, 不再发出.next事件. - 对于那些在
Subject终结后再订阅的订阅者, 也能收到一条.complete或者.error的Event, 告诉这个新订阅者, 该Subject已经终结 - 它们的区别在于 : 当一个新的订阅者刚订阅它的时候,能不能收到
Subject以前发出的旧Event, 如果能,又可以收到多少个Event.
(3) Subject 的常用方法
- onNext() :
on(.next):的简写, 该方法相当于subject接收到一个.next事件. - onError() :
on(.error):的简写, 该方法相当于subject接收到一个.error事件. - onCompleted() :
on(.completed):的简写, 该方法相当于subjet接收到一个.completed事件
PublishSubject
(1) 基本介绍
-
PublishSubject是最普通的Subjet, 它不需要初始值就能创建. -
PublishSubject的订阅者从开始订阅的时间点起,可以收到订阅Subject发出的新的Event, 而不会收到他们在订阅前已发出的Event.

PublishSubject.png
(2)案例
override func viewDidLoad() {
super.viewDidLoad()
let disposeBag = DisposeBag()
//创建一个PublishSubject
let subject = PublishSubject<String>()
subject.onNext("11") //此时没有订阅者,不会输出
//首次订阅
subject.subscribe(onNext: { str in
print("第一次订阅: ", str)
}, onCompleted: {
print("第一次订阅 : onCompleted")
}).disposed(by: disposeBag)
//有订阅者,会输出
subject.onNext("22")
subject.subscribe(onNext: { (str) in
print("第二次订阅: ", str)
}, onCompleted: {
print("第二次订阅 : onCompleted")
}).disposed(by: disposeBag)
subject.onNext("33")//两个订阅者,输出两遍
subject.onCompleted()//结束两个订阅者,打印两遍
subject.onNext("44")//再次发送event,不会打印
//再有新的订阅者,会收到onCompleted消息,通知新的订阅者,该Subject已经终结
subject.subscribe(onNext: { (str) in
print("第三次订阅: ", str)
}, onCompleted: {
print("第三次订阅 : onCompleted")
}).disposed(by: disposeBag)
}
//输出结果
第一次订阅: 22
第一次订阅: 33
第二次订阅: 33
第一次订阅 : onCompleted
第二次订阅 : onCompleted
第三次订阅 : onCompleted
BehaviorSubject
(1) 基本介绍
-
BehaviorSubject需要通过一个默认初始值来创建 - 当一个订阅者来订阅它的时候, 这个订阅者会立即收到
BehaviorSubject上一个发出的event, 之后就是正常流程
BehaviorSubject.png
(2) 使用示例
override func viewDidLoad() {
super.viewDidLoad()
let disposeBag = DisposeBag()
let subject = BehaviorSubject(value: "111")
//第一次订阅subject(先发出上一个event)
subject.subscribe { (event) in
print("第一次订阅: ", event)
}.disposed(by: disposeBag)
//发送next事件
subject.onNext("222")
subject.onError(NSError(domain: "local", code: 0, userInfo: nil))
//重复结束event,输出error
subject.subscribe { (event) in
print("第二次订阅: ",event)
}.disposed(by: disposeBag)
}
//输出结果
第一次订阅: next(111)
第一次订阅: next(222)
第一次订阅: error(Error Domain=local Code=0 "(null)")
第二次订阅: error(Error Domain=local Code=0 "(null)")
ReplaySubject
(1) 基本介绍
-
ReplaySubject在创建的时候需要设置一个bufferSize, 表示它发送过的event缓存个数. 比如 : 一个ReplaySubject的bufferSize设置为2, 它发出了三个.next的event, 那么这个subscriber就会立即收到前面缓存的两个.next的event
(2) 时序图
-
ReplaySubject的bufferSize为2 - 下面两条订阅, 订阅时间点不同.
ReplaySubject的订阅者一开始就能受到ReplaySubject之前发出的两个Event(如果有的话).
ReplaySubject.png
(3)案例
override func viewDidLoad() {
super.viewDidLoad()
let disposeBag = DisposeBag()
let subject = ReplaySubject<String>.create(bufferSize: 2);
//连续发出三个event
subject.onNext("1")
subject.onNext("2")
subject.onNext("3")
//第一次订阅
subject.subscribe { (event) in
print("第一次订阅", event)
}.disposed(by: disposeBag)
subject.onNext("4")
subject.subscribe { (event) in
print("第二次订阅", event)
}
subject.onCompleted();
subject.subscribe { (event) in
print("第三次订阅", event)
}.disposed(by: disposeBag)
}
//输出结果
第一次订阅 next(2)
第一次订阅 next(3)
第一次订阅 next(4)
第二次订阅 next(3)
第二次订阅 next(4)
第一次订阅 completed
第二次订阅 completed
第三次订阅 next(3)
第三次订阅 next(4)
第三次订阅 completed
BehaviorRelay
(1) 基本介绍
-
BehaviorRelay是作为Variable的替代者出现的. 它的本质其实也是对BehaviorRelay的封装, 所以它也必须要通过一个默认的初始值进行创建 -
BehaviorReplay具有BehaviorSubject的功能, 能够向它的订阅者发出上一个event以及之后新创建的event - 与
BehaviorSubject不同的是,不需要也不能手动给BehaviorReply发送completed或者error事件来结束它(BehaviorRelay会在销毁时自动发送.complete的 event)。 -
BehaviorReplay有一个value属性, 我们通过这个属性可以获取最新值. 而通过它的accept()方法可以对值进行修改.
(2) 案例
override func viewDidLoad() {
super.viewDidLoad()
let disposeBag = DisposeBag()
let subject = BehaviorRelay<String>(value: "111");
// 修改value值
subject.accept("222");
//第一次订阅
subject.subscribe { (event) in
print("第一次订阅: ", event)
}.disposed(by: disposeBag)
//修改value值
subject.accept("333")
subject.subscribe { (event) in
print("第二次订阅 :", event)
}.disposed(by: disposeBag)
subject.accept("444")
}
//输出结果
第一次订阅: next(222)
第一次订阅: next(333)
第二次订阅 : next(333)
第一次订阅: next(444)
第二次订阅 : next(444)

