RxSwift中的Disposable销毁者

销毁方式一般有两种:

  • 主动调用dispose进行销毁
  • 加入到销毁袋DisposeBag

dispose

我们先分析直接调用dispose进行销毁。

        // 创建序列
        let ob = Observable.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)
    }
  • 即是由disposable1disposable2创建的一个二元销毁者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),也就是Producersubscribe方法中返回的闭包SinkDisposer

4、弄清了dispose 其实就是一个二元销毁者BinaryDisposable,所以dispose.dispose()就直接来到BinaryDisposabledispose方法

5、BinaryDisposabledispose方法:

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

第一次返回的是oldValue0,后面进行按位运算过后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
    }
}
  • 依次执行sinksubscriptiondispose方法
  • 都执行完成过后,才能销毁sinksubscription,不然dispose会执行不了
  • 这里的sink就是AnonymousObservableSink
  • 这里的_subscription就是
func run(_ parent: Parent) -> Disposable {
        return parent._subscribeHandler(AnyObserver(self)) // 外界创建序列后面的闭包,返回的是一个带闭包的销毁者
    }

这段代码返回的闭包,也就是外面创建序列时,里面返回的带有闭包的销毁者,也是AnonymousDisposable类型的

7、所以接下来来到AnonymousObservableSinkdispose方法,但是我们发现AnonymousObservableSink并没有自己实现dispose方法,所以我们就来到它父类sinkdispose方法

    func dispose() {
        fetchOr(self._disposed, 1)
        // cancel: 是Producer传过来的 SinkDisposer
        self._cancel.dispose()
    }
  • self._cancel.dispose()这里由执行了SinkDisposerdispose方法,但是由于是第二次了,所以不会走下面的销毁,不会造成循环调用
  • 执行完sink.dispose()所以接下来就来到第6步中的subscription.dispose(),因为第6步中知道subscription也是AnonymousDisposable类型的,所有接来下来到AnonymousDisposabledispose方法

8、AnonymousDisposabledispose方法

// 私有方法,自己处理自己的销毁,不要别人处理,方便管理
    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步中_disposable1dispose方法就执行完了,接下来就来到_disposable2dispose方法
  • 由第2步知道_disposable2也是AnonymousDisposable类型的

11、所以又来到AnonymousDisposabledispose方法,但是这里的闭包是订阅的时候,传进来的尾随闭包,所以来到闭包action()的执行:

        {
            print("销毁回调")
        }

12、到这里_disposable1_disposable2dispose都执行完了,就将销毁者置为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信号,最后走到AnonymousObservableSinkon方法中
func on(_ event: Event) {
    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()sinkdispose方法。

// 销毁
    func dispose() {
        fetchOr(self._disposed, 1)
        // cancel: 是Producer传过来的 SinkDisposer
        self._cancel.dispose()
    }

也就是SinkDisposerdispose方法,后面的流程和上面就差不多了,然后就销毁sink,并且销毁序列创建时尾随逃逸闭包中返回的销毁者AnonymousDisposable,并执行销毁者闭包,打印销毁释放了,所以在执行完毕之前,就已经先销毁了sink,并执行了所有的销毁闭包

onError的流程和onCompleted的流程基本一样

DisposeBag

使用销毁袋的写法,如下:

    var intervalOB: Observable!
    var disposeBag = DisposeBag()

        self.intervalOB = Observable.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、DisposeBaginsert方法

    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方法,也就是BinaryDisposabledispose的方法,后面就和dispose中的销毁流程一样了
  • 就算不self.disposeBag = DisposeBag()手动赋值,进行销毁,当随着控制器的生命周期结束,即控制器的属性self.disposeBag结束的时候,也会走的析构函数deinit里面,进行销毁的

总结:

  • 销毁过程,主要是将销毁者置为nil,并且如果销毁者有自己的闭包的话,执行闭包。先置为nil,后通过保存的临时闭包来执行闭包。
  • 主要是对sink进行销毁,执行sinkdispose方法,执行结束过后再将sink置为nil
  • 销毁过程只要是将可观察序列Observable和观察者observer之间的关系sink销毁,这样他们就不能再通信了,而不能销毁可观察序列Observable和观察者observer。他们会随着控制器的生命周期,或者方法的作用域而自动销毁。

最后附上一个销毁者流程图:


销毁者流程图

你可能感兴趣的:(RxSwift中的Disposable销毁者)