Swift编程swift 文章收集swift

RxSwift核心之Disposable

2019-08-07  本文已影响0人  慕_風

一般来说,一个可观察序列发出了 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相对简单一些,那我们先从简单的开始分析。 通过分析源码,可以清楚的知道,disposable 是一个保存有销毁闭包的 AnonymousDisposable 匿名销毁者。

至此,两个参数的分析结束。那我们再来分析 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.valuemask 做或 (|) 运算。并且将或运算的结果赋值给 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 = 0mask = 1,那么,最后的返回值为0,且 self._isDisposed 中的 value 变为 1。即这里的 fetchOr 函数仅在第一次执行时返回值为 0,以后均为 1
也意味着,dispose() 只会执行一次。

dispose() 对两个初始化时传入的参数都调用 dispose()。调用完成后,都置为nil,完成订阅的销毁。那么,我们按照调用顺序,再深入理解其中的销毁逻辑。

  1. self._disposable1?.dispose()
    在对 _disposable1 调用 dispose() 时,其实是调用 SinkDisposerdispose 函数。

    最终就会调用 sink.dispose()subscription.dispose()以及将 self._sinkself._subscription置为nil。
    • sink.dispose()
      sink.dispose() 就会调用 AnonymousObservableSinkdispose()。 根据源码分析,dispose() 会执行 AnonymousObservableSink 初始化时传入的 canceldispose(),而 cancel 又是 Producer.subscribe 中初始化的 SinkDisposer 实例对象。即会回到SinkDisposerdispose 函数,但是因为 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() 的调用。

  2. self._disposable2?.dispose()
    在上一节也分析了,_disposable2 是保存有订阅时 subscribe 函数的 onDisposed闭包参数的 AnonymousDisposable。其调用 dispose 函数时,也会回调其中保存的闭包 print("已销毁"),所以会打印出 已销毁

至此,Disposable 可被清除的资源 的底层分析已经完成。

总结:经过上面的销毁者源码分析,可以知道,销毁者(Disposable)的核心流程主要有3个:

  1. 销毁连接 可观察序列观察者AnonymousObservableSink 对象,打断其中连接,取消订阅。--这也是其核心逻辑
  2. 回调创建序列时返回的Disposables.create{ print("销毁释放了") } 中的闭包。
  3. 回调订阅信号时的 onDisposed 闭包。

Disposable的实际应用 DisposeBag

在通常情况下,我们是不需要手动调用 dispose 函数的,上面的示例只是为了便于分析其底层逻辑。在实际使用中,我们一般使用 DisposeBag 来自动管理订阅的生命周期。

示例:

let subject = PublishSubject<String>()

subject.onNext("🐘")

subject.subscribe(onNext: { print("订阅到了: \($0)") })
    .disposed(by: disposeBag)
其中:disposeBag 是Controller持有的属性。
当Controller被销毁时,所有的订阅都会被销毁。

下面我们来分析一下 DisposeBag 的底层实现。

以上就是 DisposeBag 的源码分析,其核心原理是在生命周期结束执行 deinit 方法时,对所有内部保存的销毁者调用 dispose 方法,完成销毁订阅的操作。

以上RxSwift核心之Disposable的底层分析,若有不足之处,请评论指正。

上一篇 下一篇

猜你喜欢

热点阅读