RxSwift(11)—— dispose源碼解析

就問此時(shí)此刻還有誰芹枷?45度仰望天空,該死莲趣!我這無處安放的魅力鸳慈!


RxSwift目錄直通車--- 和諧學(xué)習(xí),不急不躁喧伞!


在這個(gè)篇章我們分析RxSwift一個(gè)非常重要的元素 一 銷毀者走芋!這一元素也是我們 Rxswift 四俊杰之一。銷毀者Rxswift的世界里面扮演的角色也是非常重要的潘鲫,所以對(duì)它的深入解析翁逞,才能幫助我們對(duì)Rxswift更好的理解

銷毀者初探

首先給大家看一段代碼,我們從基本序列創(chuàng)建和訂閱開始分析

// 創(chuàng)建序列
let ob = Observable<Any>.create { (observer) -> Disposable in
    observer.onNext("Cooci")
    return Disposables.create {
            print("銷毀釋放了")
        }
}
// 序列訂閱
let dispose = ob.subscribe(onNext: { (anything) in
    print("訂閱到了:\(anything)")
}, onError: { (error) in
    print("訂閱到了:\(error)")
}, onCompleted: {
    print("完成了")
}) {
    print("銷毀回調(diào)")
}
  • 這段代碼里面關(guān)于銷毀者相關(guān)的就是我們創(chuàng)建序列的回調(diào)閉包
    Disposables.create {print("銷毀釋放了")}
    按照前面我給大家分享的代碼技巧溉仑,這里就不會(huì)迷路挖函!可以直接定位到核心代碼
extension Disposables {
    public static func create(with dispose:) -> Cancelable {
        return AnonymousDisposable(disposeAction: dispose)
    }
}
  • 創(chuàng)建了一個(gè)匿名銷毀者 AnonymousDisposable 跟我們的序列,訂閱者一樣的手法浊竟,不同的業(yè)務(wù)邏輯必然還有其他細(xì)節(jié)操作怨喘,但是我們從一般入手快速直接
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()
        }
    }
}
  • 上面我們可以看到初始化就是保存了響應(yīng)回調(diào)閉包,那么在什么時(shí)候回調(diào)呢振定?就在下面我們標(biāo)記的核心邏輯代碼 - dispose()
  • fetchOr(self._isDisposed, 1) 是一個(gè)單項(xiàng)標(biāo)記手段必怜,我們一般操作就是屬性標(biāo)記,這里利用的是更裝逼的算法標(biāo)記:降低依賴和更加快速
  • 上面方法的意思就是保證只會(huì)銷毀一次
  • 下面就是對(duì)回調(diào)閉包取出然后置空銷毀 self._disposeAction = nil
  • 對(duì)取出的閉包調(diào)用執(zhí)行: action()

現(xiàn)在感覺一切很順利后频,但是聰明的我們一定要知道這里落下一個(gè)重要的前導(dǎo)因素:什么時(shí)候調(diào)用了 dispose()

銷毀調(diào)用

上面的流程梳庆,我們是在序列的回調(diào)閉包:subscriberHandle里面,其實(shí)這個(gè)流程之前還有一個(gè)非常重要的流程:訂閱 subscriber

if let disposed = onDisposed {
  disposable = Disposables.create(with: disposed)  
}else {
  disposable = Disposables.create()
 }
  • 這里就是保存外界銷毀閉包的保存 - 達(dá)到提示銷毀
switch event {
case .next(let value):
    onNext?(value)
case .error(let error):
  // 響應(yīng)外界調(diào)回閉包
    disposable.dispose()
case .completed:
  // 響應(yīng)外界調(diào)回閉包
    disposable.dispose()
}
  • 觀察者回調(diào)里面調(diào)用, 響應(yīng)外界調(diào)回閉包
  • return Disposables.create(self.asObservable().subscribe(observer),disposable) 綜合來看靠益,我們的重點(diǎn)必然在這句代碼丧肴,溝通下面流程的 subscribe, 外界訂閱返回的銷毀者(可以隨時(shí)隨地進(jìn)行 dispose.dispose()
  • 上面代碼跟進(jìn)去看到BinaryDisposable(disposable1, disposable2) 原來創(chuàng)建的二元銷毀者!
func dispose() {
    if fetchOr(self._isDisposed, 1) == 0 {
        self._disposable1?.dispose()
        self._disposable2?.dispose()
        self._disposable1 = nil
        self._disposable2 = nil
    }
}
  • 二元銷毀者的 dispose 方法也在預(yù)料之中胧后,分別銷毀
  • 那么我們的重點(diǎn)就應(yīng)該探索芋浮,在 subscribe 這里面創(chuàng)建的關(guān)鍵銷毀者是什么?
  • 下面我們進(jìn)入非常熟悉的:Producer
let disposer = SinkDisposer()
let sinkAndSubscription = self.run(observer, cancel: disposer)
disposer.setSinkAndSubscription(sink: sinkAndSubscription.sink,
 subscription: sinkAndSubscription.subscription)
// 返回銷毀者
return disposer
  • 看到 SinkDisposer 我心里舒服了壳快!一切都是那么熟悉,普通銷毀者:AnonymousDisposable , 關(guān)鍵銷毀者: SinkDisposer
  • 首先我們不著急具體去查閱 SinkDisposer 里面實(shí)現(xiàn)
  • 先看什么東西進(jìn)入了 SinkDisposer
  • self.run(observer, cancel: disposer) 證明里面需要用到 SinkDisposer
  • disposer.setSinkAndSubscription 常規(guī)操作,也看看源碼把
func setSinkAndSubscription(sink: Disposable, subscription: Disposable) {
    self._sink = sink
    self._subscription = subscription

// 獲取狀態(tài) 
    let previousState = fetchOr(self._state, 
DisposeState.sinkAndSubscriptionSet.rawValue)

// 如果狀態(tài)滿足就銷毀
    if (previousState & DisposeState.disposed.rawValue) != 0 {
        sink.dispose()
        subscription.dispose()
        self._sink = nil
        self._subscription = nil
    }
}
  • 保存了兩個(gè)屬性 : sinksubscription(就是外界創(chuàng)建序列的閉包的返回銷毀者)
  • 取了某一個(gè)狀態(tài):previousState,判斷狀態(tài)的條件七婴,然后執(zhí)行 這兩個(gè)保存屬性的銷毀和置空釋放銷毀 : .dispose() + = nil
  • 其實(shí)是可以理解修肠,就是我們?cè)诩尤氲臇|西其實(shí)需要銷毀的嵌施,不應(yīng)該保留的吗伤,那么沒必要給它繼續(xù)保留生命跡象

OK 剩下我們還去一個(gè)傳進(jìn)去的銷毀者,去干嗎?我們也跟一下源碼!

// 創(chuàng)建 sink 保存了銷毀者
let sink = AnonymousObservableSink(observer: observer, cancel: cancel)

// 中間流程省略泣栈。掺涛。。拣帽。

func on(_ event: Event<Element>) {
    switch event {
    case .next:
        self.forwardOn(event)
    case .error, .completed:
        if fetchOr(self._isStopped, 1) == 0 {
            self.forwardOn(event)
            // 關(guān)鍵點(diǎn):完成和錯(cuò)誤信號(hào)的響應(yīng)式必然會(huì)直接開啟銷毀的
            self.dispose()
        }
    }
}
  • 完成和錯(cuò)誤信號(hào)的響應(yīng)式必然會(huì)直接開啟銷毀的 : self.dispose()! 這里也解釋了:一旦我們的序列發(fā)出完成或者錯(cuò)誤就無法再次響應(yīng)了区丑!
  • 剩下一個(gè)BIG問題: 到底我們的銷毀的是什么
func dispose() {
    let previousState = fetchOr(self._state, DisposeState.disposed.rawValue)

    if (previousState & DisposeState.sinkAndSubscriptionSet.rawValue) != 0 {
        sink.dispose()
        subscription.dispose()

        self._sink = nil
        self._subscription = nil
    }
}
  • 無論我們直接銷毀還是系統(tǒng)幫助我們銷毀必然會(huì)調(diào)用:dispose()
  • 我們查看 dispose() 得出: 就是在初始化初期我們保留的兩個(gè)屬性的操作
  • sink.dispose() + self._sink = nil & subscription.dispose() + self._subscription = nil 執(zhí)行相關(guān)釋放和銷毀
  • 如果你細(xì)細(xì)品來你會(huì)慢慢感知到:這種設(shè)計(jì)是對(duì)的!
  • 我們?cè)?RxSwift 的世界里最重要的東西啥纸,我們就是通過:序列,觀察者 來建立響應(yīng)關(guān)系!如果我們斷開了響應(yīng)關(guān)系不就達(dá)到銷毀的目標(biāo)穗酥?然而我們斷開響應(yīng)關(guān)系最重要的就是:Sink
  • 很多同學(xué)可能會(huì)問:那么我們創(chuàng)建的序列节吮、觀察者對(duì)象怎么辦透绩?你不管了碳竟?
  • 第一:內(nèi)部創(chuàng)建的臨時(shí)序列和觀察者都會(huì)隨著對(duì)外的觀察者和序列的生命周期而銷毀釋放。
  • 第二:外界觀察者和序列會(huì)隨著他們的作用域空間而釋放
  • 第三:釋放不了只是對(duì)象的釋放有問題仙蚜,常規(guī)內(nèi)存管理問題
  • 第四:最為一個(gè)再牛逼的框架也不能對(duì)程序員寫的代碼直接管理控制
  • 第五:RxSwift 的觀察和序列以及銷毀者就是普通對(duì)象娶桦,ARC 申請(qǐng)開辟內(nèi)存栗涂,開發(fā)人員正常處理就OK

RxSwift 的銷毀者的設(shè)計(jì)個(gè)人感覺還是比較精妙的菩混,對(duì)于整個(gè)框架的連貫和整體性再次驗(yàn)證疚脐!希望讀者讀者用心感受設(shè)計(jì)思路疟游!

就問此時(shí)此刻還有誰颁虐?45度仰望天空役耕,該死!我這無處安放的魅力聪廉!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末瞬痘,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子板熊,更是在濱河造成了極大的恐慌框全,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,755評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件干签,死亡現(xiàn)場(chǎng)離奇詭異津辩,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)容劳,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門喘沿,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人竭贩,你說我怎么就攤上這事蚜印。” “怎么了留量?”我有些...
    開封第一講書人閱讀 165,138評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵窄赋,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我楼熄,道長(zhǎng)忆绰,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,791評(píng)論 1 295
  • 正文 為了忘掉前任可岂,我火速辦了婚禮错敢,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘缕粹。我一直安慰自己稚茅,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,794評(píng)論 6 392
  • 文/花漫 我一把揭開白布致开。 她就那樣靜靜地躺著峰锁,像睡著了一般。 火紅的嫁衣襯著肌膚如雪双戳。 梳的紋絲不亂的頭發(fā)上虹蒋,一...
    開封第一講書人閱讀 51,631評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音飒货,去河邊找鬼魄衅。 笑死,一個(gè)胖子當(dāng)著我的面吹牛塘辅,可吹牛的內(nèi)容都是我干的晃虫。 我是一名探鬼主播,決...
    沈念sama閱讀 40,362評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼扣墩,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼哲银!你這毒婦竟也來了扛吞?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,264評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤荆责,失蹤者是張志新(化名)和其女友劉穎滥比,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體做院,經(jīng)...
    沈念sama閱讀 45,724評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡盲泛,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了键耕。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片寺滚。...
    茶點(diǎn)故事閱讀 40,040評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖屈雄,靈堂內(nèi)的尸體忽然破棺而出村视,到底是詐尸還是另有隱情,我是刑警寧澤棚亩,帶...
    沈念sama閱讀 35,742評(píng)論 5 346
  • 正文 年R本政府宣布蓖议,位于F島的核電站,受9級(jí)特大地震影響讥蟆,放射性物質(zhì)發(fā)生泄漏勒虾。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,364評(píng)論 3 330
  • 文/蒙蒙 一瘸彤、第九天 我趴在偏房一處隱蔽的房頂上張望修然。 院中可真熱鬧,春花似錦质况、人聲如沸愕宋。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)中贝。三九已至,卻和暖如春臼朗,著一層夾襖步出監(jiān)牢的瞬間邻寿,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評(píng)論 1 270
  • 我被黑心中介騙來泰國(guó)打工视哑, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留绣否,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,247評(píng)論 3 371
  • 正文 我出身青樓挡毅,卻偏偏與公主長(zhǎng)得像蒜撮,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子跪呈,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,979評(píng)論 2 355