一般来说,一个可观察序列发出了 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 源码。
在之前的RxSwift核心逻辑简介中,我们仅分析了 self.asObservable().subscribe(observer)这个订阅逻辑,因为订阅流程基本是一个独立的完成逻辑,而 dispose 销毁逻辑也是一个相对独立的逻辑,所以可以分开来分析。那我们现在就来看看 Disposables.create 源码。
Disposables.create 创建了一个 BinaryDisposable 对象的实例。 BinaryDisposable 初始化时,需要两个 Disposable 参数。我们分别来分析这两个参数具体是什么,因为参数2相对简单一些,那我们先从简单的开始分析。
- 参数2
disposable:
通过subscribe源码可以知道,因为示例中onDisposed闭包有代码块print("已销毁")所以disposable = Disposables.create(with: disposed)。
通过分析源码,可以清楚的知道,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。
可能这样描述不是很清晰,那我们用图表的方式来直观展示。
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的底层分析,若有不足之处,请评论指正。












网友评论