七、销毁者Dispose
一般来说,一个可观察序列发出了 error 或者 completed 事件,那么所有内部资源都会被释放。但是如果你需要提前释放这些资源或者取消订阅的话,那么你可以对返回的 Disposable(可被清除的资源) 调用 dispose
方法。 调用 dispose
方法后,订阅将被取消,并且内部资源都会被释放掉。
7.1 案例引入
// 创建序列
let ob = Observable<Any>.create { (observer) -> Disposable in
observer.onNext("tony")
return Disposables.create { print("销毁释放了")} // dispose.dispose()
}
// 序列订阅
let dispose = ob.subscribe(onNext: { (anything) in
print("订阅到了:\(anything)")
}, onError: { (error) in
print("订阅到了:\(error)")
}, onCompleted: {
print("完成了")
}) {
print("销毁回调")
}
// 销毁关系
// status - 算法 - dispose 随时随地都能销毁
// 对象 是无法销毁的
print("执行完毕")
dispose.dispose()
/*
订阅到了:tony
执行完毕
销毁释放了
销毁回调
*/
7.2 基本源码分析
7.2.1 Disposables垃圾袋创建
- 上面案例代码中关于销毁者相关的就是我们创建序列的回调闭包
Disposables.create {print("销毁释放了")}
咱们直接定位到核心代码!看到这段代码,是不是似曾相识!在Observable
中也有它!
我们跟一下create
方法
- 创建了一个匿名销毁者
AnonymousDisposable
跟我们的序列,订阅者一样的手法,不同的业务逻辑必然还有其他细节操作,但是我们从一般入手快速直接
- 上面我们可以看到初始化就是保存了响应回调闭包,那么在什么时候回调呢?就在下面我们标记的核心逻辑代码 -
dispose()
fetchOr(self._isDisposed, 1)
是一个单项标记手段,我们一般操作就是属性标记(eg:flag)。
func fetchOr(_ this: AtomicInt, _ mask: Int32) -> Int32 {
this.lock()
let oldValue = this.value // 0 1
/// |= 按位或 运算 后再赋值,eg:C |= 2 相当于 C = C | 2
this.value |= mask // 1 1
this.unlock()
return oldValue // 0 1 1 1 1 1 1 1
}
/*
十进制:二进制
1: 01
2: 10
按位或 运算后 -> 11 -> 3
*/
self._isDisposed
值为 AtomicInt(0) 则,this.value = 0
、mask = 1
,那么,最后的返回值为0,且 self._isDisposed
中的 value
变为 1。即这里的 fetchOr
函数仅在第一次执行时返回值为 0,以后均为 1。 也意味着,dispose() 只会执行一次。
- 上面方法的意思就是保证只会销毁一次
- 下面就是对回调闭包取出然后置空销毁
self._disposeAction = nil
- 对取出的闭包调用执行:
action()
现在感觉一切很顺利,但是聪明的我们一定要知道这里落下一个重要的前导因素:什么时候调用了 dispose()
7.2.2 销毁调用
上面的流程,我们是在序列的回调闭包:subscriberHandle
里面,其实这个流程之前还有一个非常重要的流程:订阅 subscriber
if let disposed = onDisposed {
/// 保存垃圾回收袋
disposable = Disposables.create(with: disposed)
}else {
disposable = Disposables.create()
}
- 这里就是保存外界销毁闭包的保存 - 达到提示销毁
- 观察者回调里面调用, 响应外界调回闭包
return Disposables.create(self.asObservable().subscribe(observer),disposable)
综合来看,我们的重点必然在这句代码,沟通下面流程的subscribe
, 外界订阅返回的销毁者(可以随时随地进行dispose.dispose()
)- 上面代码跟进去看到
BinaryDisposable(disposable1, disposable2)
原来创建的二元销毁者
- 二元销毁者的
dispose
方法也在预料之中,分别销毁 - 那么我们的重点就应该探索,在
subscribe
这里面创建的关键销毁者是什么? - 下面我们进入非常熟悉的:
Producer
let disposer = SinkDisposer()
let sinkAndSubscription = self.run(observer, cancel: disposer)
disposer.setSinkAndSubscription(sink: sinkAndSubscription.sink,
subscription: sinkAndSubscription.subscription)
// 返回销毁者
return disposer
func setSinkAndSubscription(sink: Disposable, subscription: Disposable) {
self._sink = sink
self._subscription = subscription
// 获取状态
let previousState = fetchOr(self._state, DisposeState.sinkAndSubscriptionSet.rawValue)
// 如果状态满足就销毁
if (previousState & DisposeState.disposed.rawValue) != 0 {
sink.dispose()
subscription.dispose()
self._sink = nil
self._subscription = nil
}
}
- 保存了两个属性 :
sink
和subscription
(就是外界创建序列的闭包的返回销毁者) - 取了某一个状态:
previousState
,判断状态的条件,然后执行 这两个保存属性的销毁和置空释放销毁 :.dispose() + = nil
OK 剩下我们还去一个传进去的销毁者,跟一下源码!
// 创建 sink 保存了销毁者
let sink = AnonymousObservableSink(observer: observer, cancel: cancel)
// 中间流程省略..
func on(_ event: Event<Element>) {
switch event {
case .next:
self.forwardOn(event)
case .error, .completed:
if fetchOr(self._isStopped, 1) == 0 {
self.forwardOn(event)
// 关键点:完成和错误信号的响应式必然会直接开启销毁的
self.dispose()
}
}
}
- 完成和错误信号的响应式必然会直接开启销毁的 :
self.dispose()
! 这里也解释了:一旦我们的序列发出完成或者错误就无法再次响应了! - 剩下一个BIG问题: 到底我们的销毁的是什么
func dispose() {
let previousState = fetchOr(self._state, DisposeState.disposed.rawValue)
if (previousState & DisposeState.sinkAndSubscriptionSet.rawValue) != 0 {
sink.dispose()
subscription.dispose()
self._sink = nil
self._subscription = nil
}
}
- 无论我们直接销毁还是系统帮助我们销毁必然会调用:
dispose()
- 我们查看
dispose()
得出: 就是在初始化初期我们保留的两个属性的操作 sink.dispose() + self._sink = nil
&subscription.dispose() + self._subscription = nil
执行相关释放和销毁- 我们在 RxSwift 的世界里最重要的东西,我们就是通过:序列,观察者 来建立响应关系!如果我们断开了响应关系不就达到销毁的目标?然而我们断开响应关系最重要的就是:Sink这根管子!
7.3 总结
经过上面的销毁者源码分析,可以知道,销毁者(Disposable)的核心流程主要有3个:
- 销毁连接 可观察序列 和 观察者 的 AnonymousObservableSink 对象,打断其中连接,取消订阅。–这也是其核心逻辑
- 回调创建序列时返回的
Disposables.create{ print("销毁释放了") }
中的闭包。 - 回调订阅信号时的
onDisposed
闭包。