美文网首页
RxSwift中的Disposable销毁者

RxSwift中的Disposable销毁者

作者: 简_爱SimpleLove | 来源:发表于2019-08-25 14:30 被阅读0次

    销毁方式一般有两种:

    • 主动调用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)
        }
    
    • 即是由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<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()sinkdispose方法。

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

    也就是SinkDisposerdispose方法,后面的流程和上面就差不多了,然后就销毁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、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销毁者

          本文链接:https://www.haomeiwen.com/subject/zvznsctx.html