一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第14天,点击查看活动详情。
本文主要介绍subject的子类PublishSubject和BehaviorSubject使用和简单的原理。
1. SubjectType
对于我们的序列,通常创建的时候在subscriberHandle闭包中调用观察者observsr的onNext发送事件。比如:
//1.创建
let ob = Observable<Any>.create{ (obserber) -> Disposable in
//3.发送信号
obserber.onNext("hello")
obserber.onError(NSError.init(domain: "NetWorkError", code: 400, userInfo: nil))
//obserber.onCompleted()
return Disposables.create()
}
//2.订阅
ob.subscribe(onNext: { (value) in
print(value)
}, onError:{ (error) in
print(error)
} , onCompleted: {
print("订阅完成")
}, onDisposed: {
print("订阅销毁")
}).disposed(by: disposeBag)
很麻烦,我们希望我们可观察序列既可以具有观察者的发送事件on,也可以subscribe订阅。因此SubjectType就应运而生
协议SubjectType遵循了ObservableType协议,因此可以subscribe,同时关联类型遵循ObserverType协议,因此具备了发送事件on的能力。我们定义的类遵循该协议就具备了订阅和发送事件的能力。下面介绍下遵循该协议的类如何使用
2. PublishSubject
先看下使用
/// 订阅subscribe后才会生效
func publishSubjectMethod() {
let publishSubject = PublishSubject<Int>()
publishSubject.onNext(1)
publishSubject.onNext(2)//没有保存值
publishSubject.subscribe(onNext: {print("publishSubject第一次订阅",$0)})
.disposed(by: disposeBag)
publishSubject.onNext(3)
publishSubject.subscribe(onNext: {print("publishSubject再次订阅",$0)})
.disposed(by: disposeBag)
publishSubject.onNext(4)
}
打印结果
可以发现我们之前发送的事件没有保存,只有订阅后发送的事件才进行了回调。
1.1 初始化
查看下原理
首先它遵循了我们之前看的SubjectType协议因此具备了订阅和发送的事件的能力。其次保存了我们订阅者Observers,让它具备了状态的保存。这里举个例子
对于普通序列,订阅的时候会调用订阅闭包。但是我们其实只需要一次,通常我们可以使用
share共享
我们使用publish后connect
也是同样的效果,都是一次发送多个订阅。
2.2 订阅
对我们的数据处理进行
加锁处理
关键字defer 表示return后调用,进行解锁。我们日常开发的时候也可以这样使用。
闭包调用会synchronized_subscribe方法并传入我们外部的eventHanlde闭包。首先判断闭包的状态,我们不用太关注。
我们关注下画框的关键地方 ,这里我们observers是一个数组插入我们订阅的回调事件eventHandl即observer.on 。
SubscriptionDisposable我们看下这里保存我们key即之前的订阅事件回调数组,销毁的时候处理数组。
2.2 发送
发送的时候调用dispatch(),首先会调用里面的参数即调用synchronized_on方法
该方法可以发现会返回我们订阅的时候保存的
observers(eventHandle订阅的闭包)数组。对于complete和error事件则是处理清空。
我们这个时候会调用我们的dispatch(self.synchronized_on(event), event)。传入我们的事件回调数组,和事件类型。
首先调用事件数组的第一个闭包进行回调
我认为这样是为了
节约时间,减少一些逻辑上的处理。比我我们取数组的第一个值,没有的话就表示有问题,不用走下面的流程
因为我们开始的时候没有订阅直接发送事件,所以我们的事件回调闭包数组为空。当我们订阅的时候。进入on之后调用onCore
关于_onlyFastPath表示是否只有一个订阅者,走快速通道。
当我们有2个订阅者的时候
会获取除去第一个剩下的回调数组进行回调
- _dictionary
对于_dictionary存放的是我们最后的一个闭包回调,只有插入的时候我们回调数组大于30的时候才会存储。
3. BehaviorSubject
关于BehaviorSubject和我们的PublishSubject类似的,只是多了一个保存我们发送元素的值。
- 使用
/// 在订阅前保存一个值
func behaviorSubjectMethod() {
let behaviorSubject = BehaviorSubject<Int>.init(value: 2)
behaviorSubject.subscribe(onNext: {print("BehaviorSubject首次订阅",$0)})
.disposed(by: disposeBag)
behaviorSubject.onNext(4)
behaviorSubject.subscribe(onNext: {print("BehaviorSubject再次订阅",$0)})
.disposed(by: disposeBag)
behaviorSubject.onNext(5)
}
打印结果
我们简单分析下
- 初始化
初始化的时候会保存我们的元素
- 订阅
订阅的时候相比
PublishSubject多了一步主动调用订阅eventHandle的回调
- 发送事件
保存我们发送的元素,这样在有订阅者订阅的时候会发送
最后一次发送的元素。
4. 总结
主要介绍了PublishSubject和behaviorSubject的使用,通过详细探讨Publish Subject,让我们知道了subject具备了subscribe和on的特性,从而既能订阅也能发送响应。后面介绍下余下的几种subject使用和原理。