RXSwift之Dispose銷毀者解析

銷毀同樣是 RxSwift 中和序列,觀察,調(diào)度并列句伶,最重要的四個元素之一。
銷毀一般有兩種方法:

  • 訂閱產(chǎn)生的可 Disposable 清除資源對象配猫,單獨調(diào)用 dispose 方法進行銷毀
  • 通過將產(chǎn)生的清除對象放到 DisposeBag 中,在作用域結(jié)束后被釋放杏死,也可以在需要的時候置空釋放泵肄。

初探

那么首先從基本序列創(chuàng)建和訂閱開始分析

  • 例子:
    let ob = Observable<Any>.create { (observer) -> Disposable in
        observer.onNext("lb")
        return Disposables.create {print("銷毀釋放了")}
    }
    
    let dispose = ob.subscribe(onNext: { (element) in
        print("訂閱到了:\(element)")
    }, onError: { (error) in
        print("訂閱到了:\(error)")
    }, onCompleted: {
        print("完成")
    }) {
        print("銷毀回調(diào)")
    }
    
    print("執(zhí)行完畢")
    dispose.dispose()
  • 打印結(jié)果:

訂閱到了:lb
執(zhí)行完畢
銷毀釋放了
銷毀回調(diào)

  • 分析:
    點進去 Disposables.create 點不進去的按老方法,直接搜索找淑翼,swift 會記錄 下一次就點的進了腐巢。
extension Disposables {

    /// - parameter dispose: Disposal action which will be run upon calling `dispose`.
    public static func create(with dispose: @escaping () -> Void) -> Cancelable {
        return AnonymousDisposable(disposeAction: dispose)
    }

}

再進入 AnonymousDisposable

fileprivate final class AnonymousDisposable : DisposeBase, Cancelable {
    public typealias DisposeAction = () -> Void

    private let _isDisposed = AtomicInt(0)
    private var _disposeAction: DisposeAction?

    fileprivate init(_ disposeAction: @escaping DisposeAction) {
        self._disposeAction = disposeAction
        super.init()
    }

    fileprivate init(disposeAction: @escaping DisposeAction) {
        self._disposeAction = disposeAction
        super.init()
    }

    fileprivate func dispose() {
        if fetchOr(self._isDisposed, 1) == 0 {
            if let action = self._disposeAction {
                self._disposeAction = nil
                action()
            }
        }
    }
}

跟訂閱方法類似,同樣是產(chǎn)生了一個匿名中間類 AnonymousDisposable 玄括。使用屬性保存了銷毀閉包參數(shù)冯丙。
這個類繼承與 DisposeBase,遵循 Cancelableprotocol惠豺,而且自己實現(xiàn)了 私有方法 dispose()
這個方法中 有一個 fetchOr 方法值得一提:

func fetchOr(_ this: AtomicInt, _ mask: Int32) -> Int32 {
    this.lock()
    let oldValue = this.value
    this.value |= mask
    this.unlock()
    return oldValue
}

首先 其實現(xiàn)目的是為了保證滿足 if 條件里的代碼只執(zhí)行一次。采用與1進行位運算风宁,并且

private let _isDisposed = AtomicInt(0)

可以看出 self._isDisposed 的初始值是0洁墙,結(jié)合 fetchOr 具體方法實現(xiàn),達到只會執(zhí)行一次的效果戒财。
執(zhí)行 if 里的代碼

if let action = self._disposeAction {
     self._disposeAction = nil
     action()
}

先賦值到一個臨時變量 action 同時判斷 _disposeAction 為不為空热监,將自己的 _disposeAction 屬性置空,執(zhí)行銷毀回調(diào)饮寞。也就是我們寫的 print("銷毀釋放了")

那么這個 dispose() 方法干了啥我們搞清楚了孝扛,問題又來了 它是什么時候被調(diào)用的呢?

不著急幽崩,我們接著往下走苦始,來到我們寫的代碼中,走 ob.subscribe(onNext ... 慌申,這個方法很熟悉了陌选。直接進來

public func subscribe(onNext: ((E) -> Void)? = nil, onError: ((Swift.Error) -> Void)? = nil, onCompleted: (() -> Void)? = nil, onDisposed: (() -> Void)? = nil)
    -> Disposable {
        let disposable: Disposable
        
        if let disposed = onDisposed {
            disposable = Disposables.create(with: disposed)
        }
        else {
            disposable = Disposables.create()
        }
            
        let observer = AnonymousObserver<E> { event in
            switch event {
            case .next(let value):
                onNext?(value)
            case .error(let error):
                if let onError = onError {
                    onError(error)
                }
                else { ... }
                disposable.dispose()
            case .completed:
                onCompleted?()
                disposable.dispose()
            }
        }
        return Disposables.create(
            self.asObservable().subscribe(observer),
            disposable
        )
}

這個方法中首先 Disposables.create 創(chuàng)建 Disposables 并保存了外界傳遞的銷毀回調(diào) 也就是我們寫的

print("銷毀回調(diào)")

接下來來到重點:

return Disposables.create(
   self.asObservable().subscribe(observer),
   disposable
)

這里可以看到, 它就是我們外界訂閱調(diào)用 subscribe 方法得到的返回,并且外界可以隨時調(diào)用這個返回的對象的 .dispose() 方法進行銷毀.

直接點進去 .create方法

public static func create(_ disposable1: Disposable, _ disposable2: Disposable) -> Cancelable {
   return BinaryDisposable(disposable1, disposable2)
}

繼續(xù)進去該類 找 dispose 方法

func dispose() {
    if fetchOr(self._isDisposed, 1) == 0 {
        self._disposable1?.dispose()
        self._disposable2?.dispose()
        self._disposable1 = nil
        self._disposable2 = nil
    }
}

這個二元銷毀者的 dispose 方法也是常規(guī)操作,分別銷毀. 值得一提的是它是一個開放出來的方法,因此外界可以隨時調(diào)用該對象的銷毀方法.

  • 接下來 回到 self.asObservable().subscribe(observer)
    不做贅述. 直接找 Producersubscribe 方法
    let disposer = SinkDisposer()
    let sinkAndSubscription = self.run(observer, cancel: disposer)
    disposer.setSinkAndSubscription(sink: sinkAndSubscription.sink, subscription: sinkAndSubscription.subscription)

    return disposer

run方法由子類自己實現(xiàn) ,從而來到 AnonymousObservablerun 方法中

override func run<O : ObserverType>(_ observer: O, cancel: Cancelable) -> (sink: Disposable, subscription: Disposable) where O.E == Element {
    let sink = AnonymousObservableSink(observer: observer, cancel: cancel)
    let subscription = sink.run(self)
    return (sink: sink, subscription: subscription)
}

眾所周知 sink.run 就是調(diào)用
這個 subscription 就是 AnonymousDisposable。(原因是 sink.run 就是調(diào)用 AnonymousObservable 中保存的 _subscribeHandler 回調(diào) 也就是用戶創(chuàng)建 create 時初始化傳進來的). 而且我們 create 閉包中返回的是
AnonymousDisposable
也就是這句我們自己寫的代碼

let ob = Observable<Any>.create { (observer) -> Disposable in
   observer.onNext("lb")
   return Disposables.create {print("銷毀釋放了")}
}

然后就把 AnonymousObservableSinkAnonymousDisposable 打包進元組給返回了咨油。

再繼續(xù)看 SinkDisposersetSinkAndSubscription

func setSinkAndSubscription(sink: Disposable, subscription: Disposable) {
    self._sink = sink
    self._subscription = subscription

    let previousState = fetchOr(self._state, DisposeState.sinkAndSubscriptionSet.rawValue)
    if (previousState & DisposeState.sinkAndSubscriptionSet.rawValue) != 0 {
        rxFatalError("Sink and subscription were already set")
    }

    if (previousState & DisposeState.disposed.rawValue) != 0 {
        sink.dispose()
        subscription.dispose()
        self._sink = nil
        self._subscription = nil
    }
}
  • 保存了 sinksubscription (就是外界創(chuàng)建序列的閉包的返回銷毀者)
  • 取了某一個狀態(tài):previousState ,判斷狀態(tài)的條件您炉,然后執(zhí)行 這兩個保存屬性的銷毀和置空釋放銷毀

最后回來到外部我們自己敲的代碼中
來到

dispose.dispose()

也就是調(diào)用 BinaryDisposable 二元的銷毀者的 .dispose() 方法一一銷毀. 方法實現(xiàn)前面提到.

至此整個流程走完. 最值得一提的是

我們在 RxSwift 的世界里最重要的東西 -- 管道 sink,我們就是通過銷毀 sink中保存的屬性以及關聯(lián) 來實現(xiàn)銷毀響應流程.

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末役电,一起剝皮案震驚了整個濱河市赚爵,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌法瑟,老刑警劉巖冀膝,帶你破解...
    沈念sama閱讀 218,204評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件瓢谢,死亡現(xiàn)場離奇詭異畸写,居然都是意外死亡,警方通過查閱死者的電腦和手機氓扛,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,091評論 3 395
  • 文/潘曉璐 我一進店門枯芬,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人采郎,你說我怎么就攤上這事千所。” “怎么了蒜埋?”我有些...
    開封第一講書人閱讀 164,548評論 0 354
  • 文/不壞的土叔 我叫張陵淫痰,是天一觀的道長。 經(jīng)常有香客問我整份,道長待错,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,657評論 1 293
  • 正文 為了忘掉前任烈评,我火速辦了婚禮火俄,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘讲冠。我一直安慰自己瓜客,他們只是感情好,可當我...
    茶點故事閱讀 67,689評論 6 392
  • 文/花漫 我一把揭開白布竿开。 她就那樣靜靜地躺著谱仪,像睡著了一般。 火紅的嫁衣襯著肌膚如雪否彩。 梳的紋絲不亂的頭發(fā)上疯攒,一...
    開封第一講書人閱讀 51,554評論 1 305
  • 那天,我揣著相機與錄音列荔,去河邊找鬼卸例。 笑死称杨,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的筷转。 我是一名探鬼主播姑原,決...
    沈念sama閱讀 40,302評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼呜舒!你這毒婦竟也來了锭汛?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,216評論 0 276
  • 序言:老撾萬榮一對情侶失蹤袭蝗,失蹤者是張志新(化名)和其女友劉穎唤殴,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體到腥,經(jīng)...
    沈念sama閱讀 45,661評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡朵逝,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,851評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了乡范。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片配名。...
    茶點故事閱讀 39,977評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖晋辆,靈堂內(nèi)的尸體忽然破棺而出渠脉,到底是詐尸還是另有隱情,我是刑警寧澤瓶佳,帶...
    沈念sama閱讀 35,697評論 5 347
  • 正文 年R本政府宣布芋膘,位于F島的核電站,受9級特大地震影響霸饲,放射性物質(zhì)發(fā)生泄漏为朋。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,306評論 3 330
  • 文/蒙蒙 一厚脉、第九天 我趴在偏房一處隱蔽的房頂上張望习寸。 院中可真熱鬧,春花似錦器仗、人聲如沸融涣。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,898評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至剃斧,卻和暖如春轨香,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背幼东。 一陣腳步聲響...
    開封第一講書人閱讀 33,019評論 1 270
  • 我被黑心中介騙來泰國打工臂容, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留科雳,地道東北人。 一個月前我還...
    沈念sama閱讀 48,138評論 3 370
  • 正文 我出身青樓脓杉,卻偏偏與公主長得像糟秘,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子球散,可洞房花燭夜當晚...
    茶點故事閱讀 44,927評論 2 355