一起养成写作习惯!这是我参与「掘金日新计划 · 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使用和原理。