一需求
开发中有时候会碰到一种需求:当某一个网络请求正在请求的过程中,别的地方又发起同样的一个网络请求,此时要求不再发送同样的请求,而正在发生的请求拿到数据后要返回给两个发起者,如图
二解决
RxSwift里就有这种问题的解决方式。代码如下:我们用sleep(2)
模拟网络请求
let netOB = Observable<Any>.create { (observer) -> Disposable in
sleep(2)// 模拟网络延迟
print("我开始请求网络了")
observer.onNext("请求结果")
observer.onNext("请求结果")
observer.onCompleted()
return Disposables.create {
print("销毁回调了")
}
}
.publish()
netOB.subscribe(onNext: { (anything) in
print("发起者1订阅到了:",anything)
}).disposed(by: disposeBag)
netOB.subscribe(onNext: { (anything) in
print("发起者2订阅到了:",anything)
}).disposed(by: disposeBag)
_ = netOB.connect()
打印结果为
我开始请求网络了
发起者1订阅到了: 请求结果
发起者2订阅到了: 请求结果
发起者1订阅到了: 请求结果
发起者2订阅到了: 请求结果
销毁回调了
我们可以看到,请求只发送了一次,两个订阅者都拿到了请求结果。
三原理
这种资源共享的观察者模式,跟普通观察者模式表现上的区别仅仅在于多了个.publish()
与netOB.connect()
先看一下.publish()
的原理,点进去
继续查看
multicast
这里返回了一个
ConnectableObservableAdapter
类,并传入了两个参数:AnonymousObservable
和subject
。AnonymousObservable
我们已经非常熟悉,至于subject
我们先不管,只需要记住这里传了进去一个普通的subject
类。具体内容我们后边再看。
我们再来看我们写的代码
此时我们能发现,这个
netOB
已经不再是我们熟悉的AnonymousObservable
类。而是一个ConnectableObservableAdapter
类。这个类持有了AnonymousObservable
类(此类类通过create持有了网络请求的闭包,详见底层原理探究一篇)与一个subject
类。
继续看订阅方法
这个subscribe的实现我们已经很熟悉了
这里标注的地方不再是
AnonymousObservable
类而是ConnectableObservableAdapter
类。所以我们点进去subscribe
这里的
self.lazySubject
就是我们的之前提到的subject
类,我们继续跟进去核心代码已经被我圈出来。这里的
_observers
其实是个Bag
袋子。而这一步的操作是把observer.on
方法,插入到袋子中,我们继续跟进这个insert操作。可以看出,这里把
observer.on
方法与key
做了映射。并把所有的observer闭包都存储了起来再来看connect()
方法,点进去
我们应当注意到:
①图中的核心参数,就是之前提到的
subject
②图中的参数一,就是
AnonymousObservable
类③核心方法,其实也就是调用了
producer
的subscribe
方法。④
subscribe
方法,把connection
作为参数传递了进去,而connection
持有了subject
类。而此时的subject
类已经持有了我们所有的订阅。接下来就又进入我们熟悉的领域:
producer
调用了子类的 run
, 而 run
创建了sink
类,sink
类调用自己的run
方法实现了_subscribeHandler(AnyObserver(self))
方法,而此时sink
已经持有了connection
方法
现在_subscribeHandler(AnyObserver(self))
方法已经被调用了,也就是说我们封装在闭包里的请求方法已经被调用了。之后的问题就在于onNext方法是怎么实现的。
我们查看onNext的实现
依然是我们熟悉的on方法的调用,并把
.next
作为事件传了进去,继续点进去又到了
AnyObserver
的on方法。接下来,就是我们陌生的领域如果之前你留意过的话,这里能知道这个
self.observer
其实就是connection.on
方法。而这里的意思就是把event
方法作为参数传入connection.on
方法。我们再回到
connection.on
方法中,实现如下:还记得这个subjectObserver
类吗,这就是前文提到的subject
类。也就是说调用connection.on
方法,其实就是调用了subject
类的on
方法。我们继续看这个subject
类的on
方法
我们前文提到过,这个
_observers
就是Bag。那们点进去看这个dispatch
是不是突然就什么都明白了。在这个
dispatch
方法里,遍历了我们之前存储的observer
,而onNext
作为参数传了进去,从而实现了订阅。
总结
一:publish
存储了观察者闭包并创建了一个PublishSubject
类。
二:PublishSubject
类又存储了所有的订阅。
三:当调用connect
方法时,第一步实现了观察者闭包,第二步遍历PublishSubject
类里存储的订阅,并把把观察者闭包里的.onNext之类的核心方法作为参数,传入其中,从而实现订阅。