销毁方式一般有两种:
- 主动调用
dispose
进行销毁 - 加入到销毁袋
DisposeBag
中
dispose
我们先分析直接调用dispose
进行销毁。
// 创建序列
let ob = Observable<Any>.create { (observer) -> Disposable in
observer.onNext("Cooci")
// observer.onCompleted()
return Disposables.create {
print("销毁释放了")
}
}
// 序列订阅
let dispose = ob.subscribe(onNext: { (anything) in
print("订阅到了:\(anything)")
}, onError: { (error) in
print("订阅到了:\(error)")
}, onCompleted: {
print("完成了")
}) {
print("销毁回调")
}
print("执行完毕")
dispose.dispose() // 进行销毁
/*
输出结果:
订阅到了:Cooci
执行完毕
销毁释放了
销毁回调
*/
上面代码,我们创建了一个序列,并订阅了事件,最后调用dispose.dispose()
进行销毁。我们先不管前面创建的流程,直接断点到dispose.dispose()
这句,看看这句销毁代码里面到底做了哪些事情。
1、我们先要知道dispose
是什么,点上面它的创建方法subscribe(onNext:
进去看:
return Disposables.create(
self.asObservable().subscribe(observer), // Producer里面的SinkDisposer
disposable // 上面创建的,包含闭包的销毁者,即最外面的 “print("销毁回调")” 这句打印的闭包
)
2、发现它是由两个销毁者作为参数创建的一个新的销毁者,点击create
进去:
public static func create(_ disposable1: Disposable, _ disposable2: Disposable) -> Cancelable {
// 二元销毁者 由两个销毁者创建,同时销毁两个
return BinaryDisposable(disposable1, disposable2)
}
- 即是由
disposable1
和disposable2
创建的一个二元销毁者BinaryDisposable
。 - 这里的
disposable2
即是上面第1步中的disposable
,也就是订阅的时候,通过外面传进来的销毁闭包创建的,是AnonymousDisposable
类型的
// onDisposed闭包存在,就用onDisposed来创建一个销毁disposable
// disposable也是AnonymousDisposable类型的
if let disposed = onDisposed {
disposable = Disposables.create(with: disposed)
}
else {
disposable = Disposables.create()
}
3、第2步中的disposable1
就是第1步中的self.asObservable().subscribe(observer)
,也就是Producer
的subscribe
方法中返回的闭包SinkDisposer
4、弄清了dispose
其实就是一个二元销毁者BinaryDisposable
,所以dispose.dispose()
就直接来到BinaryDisposable
的dispose
方法
5、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, 1)
函数保证只是第一次等于0
,进来销毁,后面一直都是1
,不会进行重复销毁
func fetchOr(_ this: AtomicInt, _ mask: Int32) -> Int32 {
this.lock()
let oldValue = this.value // 0 1
// 按位或运算后再赋值 C |= 2 相当于 C = C | 2
// https://www.runoob.com/swift/swift-operators.html
this.value |= mask // 1 1 因为mask是1,所以按位运算后,始终都是1
this.unlock()
return oldValue // 0 1 1 1 1 1 1 1
第一次返回的是oldValue
即0
,后面进行按位运算过后this.value
的值始终都是1
,所以只是第一次等于0
的时候,才会进去走销毁
- 先调用
_disposable1
的销毁方法self._disposable1?.dispose()
-
_disposable1
的销毁方法执行完了过后,才会执行_disposable2
的销毁方法
6、_disposable1
的销毁方法 也就是第1步中SinkDisposer
的销毁方法
func dispose() {
let previousState = fetchOr(self._state, DisposeState.disposed.rawValue)
// 保证只是第一次进来的时候,才走下面的销毁
if (previousState & DisposeState.disposed.rawValue) != 0 {
return
}
if (previousState & DisposeState.sinkAndSubscriptionSet.rawValue) != 0 {
sink.dispose() // AnonymousObservableSink的dispose方法,如果它没有实现,就找它父类sink的dispose方法
subscription.dispose() // 就是外面创建序列闭包里面返回的销毁者
// 销毁完成过后,才能置为nil,不然dispose里面的事情都执行不完
self._sink = nil
self._subscription = nil
}
}
- 依次执行
sink
和subscription
的dispose
方法 - 都执行完成过后,才能销毁
sink
和subscription
,不然dispose
会执行不了 - 这里的
sink
就是AnonymousObservableSink
- 这里的
_subscription
就是
func run(_ parent: Parent) -> Disposable {
return parent._subscribeHandler(AnyObserver(self)) // 外界创建序列后面的闭包,返回的是一个带闭包的销毁者
}
这段代码返回的闭包,也就是外面创建序列时,里面返回的带有闭包的销毁者,也是AnonymousDisposable
类型的
7、所以接下来来到AnonymousObservableSink
的dispose
方法,但是我们发现AnonymousObservableSink
并没有自己实现dispose
方法,所以我们就来到它父类sink
的dispose
方法
func dispose() {
fetchOr(self._disposed, 1)
// cancel: 是Producer传过来的 SinkDisposer
self._cancel.dispose()
}
-
self._cancel.dispose()
这里由执行了SinkDisposer
的dispose
方法,但是由于是第二次了,所以不会走下面的销毁,不会造成循环调用 - 执行完
sink.dispose()
所以接下来就来到第6步中的subscription.dispose()
,因为第6步中知道subscription
也是AnonymousDisposable
类型的,所有接来下来到AnonymousDisposable
的dispose
方法
8、AnonymousDisposable
的dispose
方法
// 私有方法,自己处理自己的销毁,不要别人处理,方便管理
fileprivate func dispose() {
// 判断是否被销毁过,如果已经被销毁过,下面代码不用执行
// 是否为第一次进来的销毁
if fetchOr(self._isDisposed, 1) == 0 {
// 只有第一次销毁的时候,才能进来
if let action = self._disposeAction {
// 将闭包置空销毁
// 为了避免闭包里面有耗时的操作,不能及时销毁,所以用一个临时变量action保存,再执行闭包
self._disposeAction = nil
action() // 执行外面的销毁闭包,即那个打印
}
}
}
- 这里使用
fileprivate
修饰方法,使它变为一个私有方法,自己处理自己的销毁,方便管理 - 使用了
fetchOr
函数,保证只是执行一次销毁闭包 -
_disposeAction
即是外面的闭包print("销毁释放了")
这句话 - 这里可以先将闭包
_disposeAction
置为nil
,然后执行销毁之前保存的临时闭包,这样可以避免闭包里面有耗时操作,不能及时销毁 - 第6步中,因为
dispose
是一个方法,不能先保存一个临时方法,所以只有先执行完dispose
方法,再将_sink
和_subscription
置为nil
- 接下来来到闭包执行
action()
9、执行闭包action()
return Disposables.create {
print("销毁释放了")
}
- 打印
销毁释放了
10、subscription.dispose()
执行完过后,就将外面置为nil
self._sink = nil
self._subscription = nil
- 至此第5步中
_disposable1
的dispose
方法就执行完了,接下来就来到_disposable2
的dispose
方法 - 由第2步知道
_disposable2
也是AnonymousDisposable
类型的
11、所以又来到AnonymousDisposable
的dispose
方法,但是这里的闭包是订阅的时候,传进来的尾随闭包,所以来到闭包action()
的执行:
{
print("销毁回调")
}
12、到这里_disposable1
和_disposable2
的dispose
都执行完了,就将销毁者置为nil
self._disposable1 = nil
self._disposable2 = nil
至此整个销毁流程就走完了。
onCompleted和onError
如果我们把最上面dispose中代码observer.onCompleted()
这句注释放开,我们会发现打印的结果不同了,如下:
订阅到了:Cooci
完成了
销毁回调
销毁释放了
执行完毕
也就是说在执行完毕之前,就已经全部销毁完毕了
为什么会打印不一样了呢?
我们点进订阅代码中发现:
case .next(let value):
onNext?(value)
case .error(let error):
if let onError = onError {
onError(error)
}
else {
Hooks.defaultErrorHandler(callStack, error)
}
// 错误的时候销毁
disposable.dispose()
case .completed:
onCompleted?()
// 完成的时候销毁
disposable.dispose()
}
当订阅到completed
的时候:
- 会先调用执行外面传进来的完成的闭包
onCompleted
,打印完成了
- 然后调用销毁
disposable.dispose()
, 和上面第11步中一样,打印销毁回调
- 然后因为发送的
completed
信号,最后走到AnonymousObservableSink
的on
方法中
func on(_ event: Event<Element>) {
switch event {
case .next:
if load(self._isStopped) == 1 {
return
}
self.forwardOn(event)
case .error, .completed:
if fetchOr(self._isStopped, 1) == 0 {
self.forwardOn(event)
// 关键点:完成和错误信号的响应式必然会直接主动开启销毁的
self.dispose()
}
}
当收到error
或者completed
信号时,就会调用self.dispose()
即sink
的dispose
方法。
// 销毁
func dispose() {
fetchOr(self._disposed, 1)
// cancel: 是Producer传过来的 SinkDisposer
self._cancel.dispose()
}
也就是SinkDisposer
的dispose
方法,后面的流程和上面就差不多了,然后就销毁sink
,并且销毁序列创建时尾随逃逸闭包中返回的销毁者AnonymousDisposable
,并执行销毁者闭包,打印销毁释放了
,所以在执行完毕之前,就已经先销毁了sink
,并执行了所有的销毁闭包
onError的流程和onCompleted的流程基本一样
DisposeBag
使用销毁袋的写法,如下:
var intervalOB: Observable<Int>!
var disposeBag = DisposeBag()
self.intervalOB = Observable<Int>.interval(.seconds(1), scheduler: MainScheduler.init())
self.intervalOB.subscribe(onNext: { (num) in
self.showSencondNum.text = String(num)
}).disposed(by: disposeBag)
_ = self.stopAction.rx.tap.subscribe(onNext:{ [weak self]() in
print("点击按钮")
// 赋值一个新的,原来的disposeBag就会被释放,然后走deinit,也就执行deinit方法中的dispose方法,进行销毁
self?.disposeBag = DisposeBag()
})
- 注意当
subscribe
里面需要用到self
的时候,如果不用weak
修饰,会造成内存泄漏
1、点击.disposed(by: disposeBag)
进去:
extension Disposable {
public func disposed(by bag: DisposeBag) {
bag.insert(self)
}
}
- 这里的
self
并不是控制器,而是subscribe(onNext:
方法返回的二元销毁者BinaryDisposable
- 销毁袋
DisposeBag
中添加了一个self
,也就是BinaryDisposable
- 这是给
Disposable
协议扩展了一个disposed
方法,这个协议方法的核心是:
public protocol Disposable {
/// Dispose resource.
func dispose() // 核心方法: 销毁
}
上面的二元销毁者BinaryDisposable
他们也是最终遵守了Disposable
这个协议,所以才会有dispose
方法
2、DisposeBag
的insert
方法
public func insert(_ disposable: Disposable) {
self._insert(disposable)?.dispose()
}
private func _insert(_ disposable: Disposable) -> Disposable? {
self._lock.lock(); defer { self._lock.unlock() }
if self._isDisposed {
return disposable
}
// 向销毁者集合里面添加销毁者
self._disposables.append(disposable)
return nil
}
- 里面的
_disposables
是一个集合
fileprivate var _disposables = [Disposable]() // 销毁者集合
- 通过
append
方法进行添加 - 递归锁
private var _lock = SpinLock()
能够保证添加顺序
3、当外面执行self.disposeBag = DisposeBag()
这句代码的时候,就给属性self.disposeBag
赋值一个新的,原来的disposeBag
就会被释放,也就是走deinit
,也就执行deinit
方法中的dispose
方法,进行销毁
private func dispose() {
let oldDisposables = self._dispose()
// 遍历销毁者集合,全部销毁
for disposable in oldDisposables {
disposable.dispose()
}
}
private func _dispose() -> [Disposable] {
self._lock.lock(); defer { self._lock.unlock() }
let disposables = self._disposables
// 在清空集合之前,先用disposables保存
self._disposables.removeAll(keepingCapacity: false)
self._isDisposed = true
return disposables
}
deinit {
// 析构的时候销毁,调用dispose方法
self.dispose()
}
- 会将原来的集合全部清空,包括
keepingCapacity
属性置为false
,也就是取消了扩容空间 - 使用
for-in
函数,执行销毁袋中所有销毁者的dispose
方法,也就是BinaryDisposable
的dispose
的方法,后面就和dispose中的销毁流程一样了 - 就算不
self.disposeBag = DisposeBag()
手动赋值,进行销毁,当随着控制器的生命周期结束,即控制器的属性self.disposeBag
结束的时候,也会走的析构函数deinit
里面,进行销毁的
总结:
- 销毁过程,主要是将销毁者置为
nil
,并且如果销毁者有自己的闭包的话,执行闭包。先置为nil
,后通过保存的临时闭包来执行闭包。 - 主要是对
sink
进行销毁,执行sink
的dispose
方法,执行结束过后再将sink
置为nil
。 - 销毁过程只要是将可观察序列
Observable
和观察者observer
之间的关系sink
销毁,这样他们就不能再通信了,而不能销毁可观察序列Observable
和观察者observer
。他们会随着控制器的生命周期,或者方法的作用域而自动销毁。
最后附上一个销毁者流程图:
销毁者流程图
网友评论