RxSwift核心之Disposable
一般来说,一个可观察序列发出了 error 或者 completed 事件,那么所有内部资源都会被释放。但是如果你需要提前释放这些资源或者取消订阅的话,那么你可以对返回的 Disposable(可被清除的资源) 调用
dispose
方法。
调用dispose
方法后,订阅将被取消,并且内部资源都会被释放掉。
举个栗子:
// 第一步:创建序列
let ob = Observable<String>.create { (observer) -> Disposable in
// 第三步:发送信号
observer.onNext("信息1")
return Disposables.create{ print("销毁释放了") }
}
// 第二步:订阅信号
let disposable = ob.subscribe(onNext: { (text) in
print("订阅信息: \(text)")
}, onError: { (error) in
print("error: \(error)")
}, onCompleted: {
print("订阅结束")
}) {
print("已销毁")
}
// 取消订阅/释放
disposable.dispose()
执行结果:
订阅信息: 信息1
销毁释放了
已销毁
基于以上示例,来分析一下底层逻辑。
subscribe
我们再查看一下 subscribe
源码。
![](https://img.haomeiwen.com/i1820747/4bde58c9b73647cb.jpg)
self.asObservable().subscribe(observer)
这个订阅逻辑,因为订阅流程基本是一个独立的完成逻辑,而 dispose
销毁逻辑也是一个相对独立的逻辑,所以可以分开来分析。那我们现在就来看看 Disposables.create
源码。
![](https://img.haomeiwen.com/i1820747/09fd4c46905b1ec6.jpg)
![](https://img.haomeiwen.com/i1820747/19c98ac13c1be7b5.jpg)
Disposables.create
创建了一个 BinaryDisposable
对象的实例。 BinaryDisposable
初始化时,需要两个 Disposable
参数。我们分别来分析这两个参数具体是什么,因为参数2相对简单一些,那我们先从简单的开始分析。
- 参数2
disposable
:
通过subscribe
源码可以知道,因为示例中onDisposed
闭包有代码块print("已销毁")
所以disposable = Disposables.create(with: disposed)
。
![](https://img.haomeiwen.com/i1820747/a55668e7b51d505a.jpg)
disposable
是一个保存有销毁闭包的 AnonymousDisposable
匿名销毁者。
- 参数1
self.asObservable().subscribe(observer)
:
在RxSwift核心逻辑简介中已经分析了,这句代码最终会调用Producer.subscribe
所以最后会返回一个
SinkDisposer
的实例对象。SinkDisposer
也需要两个参数,而这两个参数均来自于let sinkAndSubscription = self.run(observer, cancel: disposer)
。那我们继续深入run
函数。run
函数返回一个元组,元组第一个值是sink
,第二个是sink.run(self)
返回的结果,根据RxSwift核心逻辑简介的分析可以知道,sink.run(self)
返回的结果即为创建序列的闭包返回值Disposables.create{ print("销毁释放了") }
。
至此,两个参数的分析结束。那我们再来分析 disposable.dispose()
这个流程到底做了些什么?
在分析流程之前,先插入一个小的知识点。在刚才的源码中,细心的小伙伴可以会发现,很多地方都调用了 fetchOr
函数,那么,这个函数具体是什么作用呢?我们先来分析一下。
func fetchOr(_ this: AtomicInt, _ mask: Int32) -> Int32 {
this.lock()
let oldValue = this.value
this.value |= mask
this.unlock()
return oldValue
}
这就是 fetchOr
函数源码。 lock()
只是加锁,可以不管,那么 fetchOr
函数可以简化为:
func fetchOr(_ this: AtomicInt, _ mask: Int32) -> Int32 {
let oldValue = this.value
this.value |= mask
return oldValue
}
this
是传入的AtomicInt
值,其内部仅有一个value值。
fetchOr
先将 this.value
copy一份,作为结果返回。而将 this.value
和 mask
做或 (|) 运算。并且将或运算的结果赋值给 this.value
。
可能这样描述不是很清晰,那我们用图表的方式来直观展示。
![](https://img.haomeiwen.com/i1820747/84de35ee96615738.jpg)
fetchOr
函数的作用类似于标记。具体的使用,后面再结合使用场景分析。
disposable.dispose()
经过上面的分析可以知道,示例中执行 disposable.dispose()
会调用 BinaryDisposable
中的 dispose()
函数。
func dispose() {
if fetchOr(self._isDisposed, 1) == 0 {
self._disposable1?.dispose()
self._disposable2?.dispose()
self._disposable1 = nil
self._disposable2 = nil
}
}
这里有一个 fetchOr
函数。self._isDisposed
值为 AtomicInt(0) 则,this.value = 0
、mask = 1
,那么,最后的返回值为0,且 self._isDisposed
中的 value
变为 1。即这里的 fetchOr
函数仅在第一次执行时返回值为 0,以后均为 1。
也意味着,dispose()
只会执行一次。
dispose()
对两个初始化时传入的参数都调用 dispose()
。调用完成后,都置为nil,完成订阅的销毁。那么,我们按照调用顺序,再深入理解其中的销毁逻辑。
-
self._disposable1?.dispose()
在对_disposable1
调用dispose()
时,其实是调用SinkDisposer
的dispose
函数。最终就会调用
sink.dispose()
和subscription.dispose()
以及将self._sink
和self._subscription
置为nil。-
sink.dispose()
sink.dispose()
就会调用AnonymousObservableSink
的dispose()
。 根据源码分析,dispose()
会执行AnonymousObservableSink
初始化时传入的cancel
的dispose()
,而cancel
又是Producer.subscribe
中初始化的SinkDisposer
实例对象。即会回到SinkDisposer
的dispose
函数,但是因为fetchOr
函数的存在,dispose
函数仅会执行一次。所以sink.dispose()
相当于空转一圈,什么也没有执行。 -
subscription.dispose()
在上一节的分析中,已经知道subscription
其实保存的是创建序列的闭包返回值Disposables.create{ print("销毁释放了") }
,是一个匿名销毁者AnonymousDisposable
。 即AnonymousDisposable
调用dispose()
。最终会执行保存的闭包,打印出
销毁释放了
。并将保存的闭包置为nil。 -
self._subscription = nil
释放保存的闭包。
-
self._sink = nil
将
self._sink
置为nil,是整个销毁流程中的关键。通过之前[RxSwift核心逻辑简介]的分析,已经明确了sink
的重要性,其担当起了连接 可观察序列、观察者、调度者的重要作用,现在又关联了销毁者,可以说,没有了sink
,那么所有的流程都无法正常流通了,所以将self._sink
置为nil,则打断了可观察序列和观察者之间的联系,以及释放了所有中间临时对象。
完成
self._disposable1?.dispose()
的调用。 -
-
self._disposable2?.dispose()
在上一节也分析了,_disposable2
是保存有订阅时subscribe
函数的onDisposed
闭包参数的AnonymousDisposable
。其调用dispose
函数时,也会回调其中保存的闭包print("已销毁")
,所以会打印出 已销毁。
至此,Disposable
可被清除的资源 的底层分析已经完成。
总结:经过上面的销毁者源码分析,可以知道,销毁者(Disposable)的核心流程主要有3个:
- 销毁连接 可观察序列 和 观察者 的 AnonymousObservableSink 对象,打断其中连接,取消订阅。--这也是其核心逻辑
- 回调创建序列时返回的
Disposables.create{ print("销毁释放了") }
中的闭包。- 回调订阅信号时的
onDisposed
闭包。
![]()
Disposable的实际应用 DisposeBag
在通常情况下,我们是不需要手动调用
dispose
函数的,上面的示例只是为了便于分析其底层逻辑。在实际使用中,我们一般使用 DisposeBag 来自动管理订阅的生命周期。
示例:
let subject = PublishSubject<String>()
subject.onNext("🐘")
subject.subscribe(onNext: { print("订阅到了: \($0)") })
.disposed(by: disposeBag)
其中:disposeBag 是Controller持有的属性。
当Controller被销毁时,所有的订阅都会被销毁。
下面我们来分析一下 DisposeBag
的底层实现。
-
dipsosed()
dipsosed()
是调用了DisposeBag.insert
方法,将销毁者添加到bag
中。查看
DisposeBag
的源码。insert
函数中执行了_insert
函数,并对其返回值调用dispose
方法。
因为self._isDisposed
值为false,_insert
函数返回 nil。同时将销毁者添加到self._disposables
数组中保存起来。 -
自动销毁时机
使用DisposeBag
后,不再需要我们手动管理订阅销毁,那么肯定是DisposeBag
帮我们自动处理了销毁工作。那么它是在什么时候执行销毁的呢?
DisposeBag
能 自动 管理销毁,那么只能在其生命周期函数中才能实现 自动 执行。我们继续查看其源码。我们可以在
DisposeBag
的源码中,清晰的看到deinit
方法。 其调用了自身的dispose
方法。dispose
函数中通过self._dispose()
获取到所有保存的销毁者,并对每个销毁者执行dispose
销毁操作。
_dispose
函数copy一份销毁者数组并返回。而移除self._disposables
中保存的所有元素。这样做这要是为了隔离源数据,在对销毁者执行销毁操作时,不会因外界的环境变化而对内部的销毁产生影响。
以上就是 DisposeBag 的源码分析,其核心原理是在生命周期结束执行
deinit
方法时,对所有内部保存的销毁者调用dispose
方法,完成销毁订阅的操作。
以上RxSwift核心之Disposable的底层分析,若有不足之处,请评论指正。