RxSwift核心源碼探索

響應式編程是RxSwift的核心思想,統一思想快速開發。同樣在ReactiveX系列中其他語言也都使用了這一思想,當我們掌握了RxSwift運用,那么RxJavaRxPHPRxJs等等都能夠快速上手。那么RxSwift是如何響應的呢?下面就來看一下源碼都做了哪些事情。

Rx.png

RxSwift核心流程

1、創建序列
2、訂閱序列
3、發送信號

先看一下是如何使用的,代碼如下:

//1、創建序列
let obs = Observable<Any>.create { (observer) -> Disposable in
    //3、發送信號
    observer.onNext("我是一條消息")
    return Disposables.create()
}
//2、訂閱序列
obs.subscribe(onNext: { (val) in
    //4、序列監聽
    print("onNext:\(val)")
}).disposed(by: disposeBag)//5、打包待銷毀
  • 通過Observablecreate創建序列,在create閉包內調用onNext方法實現信號發送
  • 調用subscribe方法訂閱序列,并實現subscribe的參數閉包onNext,在閉包內監聽信號
  • 最后通過disposed對序列打包等待銷毀

看到代碼可能會疑惑,消息是如何發給訂閱者的。按正常邏輯,訂閱后才能收到信息,那么可以猜測,在成為訂閱者并布置好監聽后,訂閱者向序列發送了一條消息,通知可觀察序列可以發信號了。大致可整理為如下流程:

flow.png

以上只是猜測,下面來看具體的代碼實現。在RxSwift中同名的方法有很多,很難做到直接定位代碼位置,我們可以通過command+點擊配合斷點一步步找到對應方法的底層實現。

1、創建序列

public static func create(_ subscribe: @escaping (AnyObserver<E>) -> Disposable) -> Observable<E> {
    return AnonymousObservable(subscribe)
}

該方法是對ObservableType協議的擴展,最外層實現的閉包subscribe則作為參數傳入AnonymousObservable,并返回AnonymousObservable對象,繼續執行追蹤到AnonymousObservable類,如下:

final private class AnonymousObservable<Element>: Producer<Element> {
    typealias SubscribeHandler = (AnyObserver<Element>) -> Disposable
    let _subscribeHandler: SubscribeHandler
    //初始化時保存閉包
    init(_ subscribeHandler: @escaping SubscribeHandler) {
        self._subscribeHandler = subscribeHandler
    }
    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)
    }
}

首先看一下AnonymousObservable的繼承鏈如下:

  • AnonymousObservable -> Product -> ObservableType -> ObservableConvertible

在父類Product中好像有我沒需要的方法:

override func subscribe<O : ObserverType>(_ observer: O) -> Disposable where O.E == Element {
      
}

像是訂閱方法,但不是,但也有著千絲萬縷的聯系。到此為止,序列創建部分已完成,可總結如下:

  • create方法實現參數閉包,內部創建AnonymousObservable對象
  • AnonymousObservable對象保存了外界實現的閉包
  • Producer中的subscribe方法,應該是訂閱后將要調用的方法

記住以上三點,后序逐一對比。

2、訂閱序列

根據方法名找到subscribe的實現,command+點擊直接進入實現,源碼如下(取部分源碼):

public func subscribe(onNext: ((E) -> Void)? = nil, onError: ((Swift.Error) -> Void)? = nil, onCompleted: (() -> Void)? = nil, onDisposed: (() -> Void)? = nil)
    -> Disposable {
        //此處省略若干行代碼
        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 {
                    Hooks.defaultErrorHandler(callStack, error)
                }
                disposable.dispose()
            case .completed:
                onCompleted?()
                disposable.dispose()
            }
        }
        return Disposables.create(
            self.asObservable().subscribe(observer),
            disposable
        )
}

該方法是對ObservableType的拓展。在方法內部已經出現對觀察者的定義,AnonymousObserver類型的閉包observer

源碼分析:

2.1、observer內部調用的外部(應用層)實現的閉包,由此看出所有信號是由此發出,eventobserver的參數,不難看出,observer閉包也是在其他地方調用,傳入帶有信號值的event參數

2.2、observer被當做參數傳入到subscribe中,而observer的調用必然是在subscribe中實現的

self.asObservable().subscribe(observer)

2.3、self.asObservable()該方法返回本身,保證協議的一致性,方法如下:

public class Observable<Element> : ObservableType {
    // 省去代碼若干
    public func asObservable() -> Observable<E> {
        return self
    }
}

2.4、繼續斷點執行找到subscribe方法,正是上面所提到的Producer中的方法,方法如下:

override func subscribe<O : ObserverType>(_ observer: O) -> Disposable where O.E == Element {
    // 省去代碼若干
    return CurrentThreadScheduler.instance.schedule(()) { _ in
            let disposer = SinkDisposer()
            let sinkAndSubscription = self.run(observer, cancel: disposer)
            disposer.setSinkAndSubscription(sink: sinkAndSubscription.sink, subscription: sinkAndSubscription.subscription)

            return disposer
        }
}

2.5、緊接著我的observer觀察者被傳入到run中,上面說到該觀察者一定會被調用,繼續深入

let sinkAndSubscription = self.run(observer, cancel: disposer)

2.6、繼續斷點執行,發現self.run的調用,調用的是AnonymousObservable中的run方法,代碼如下:

final private class AnonymousObservable<Element>: Producer<Element> {
    typealias SubscribeHandler = (AnyObserver<Element>) -> Disposable

    let _subscribeHandler: SubscribeHandler

    init(_ subscribeHandler: @escaping SubscribeHandler) {
        self._subscribeHandler = subscribeHandler
    }

    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)
    }
}

2.7、此處就是創建序列時的AnonymousObservable類。在run方法類創建了sink對象,在初始化時傳入了我們上面所說的觀察者,記住sink保存了觀察者observer閉包,并且調用了sink.run(self)方法,傳入的是創建時產生的可觀察序列observable閉包對象,深入run

final private class AnonymousObservableSink<O: ObserverType>: Sink<O>, ObserverType {
    typealias E = O.E
    typealias Parent = AnonymousObservable<E>
          // 省去代碼若干
    // 此處向父類Sink初始化了observer對象
    override init(observer: O, cancel: Cancelable) {
        super.init(observer: observer, cancel: cancel)
    }
    func run(_ parent: Parent) -> Disposable {
        return parent._subscribeHandler(AnyObserver(self))
    }
}

2.8、撥開云霧見天日,此處parentlet subscription = sink.run(self)傳入,self即為創建序列create方法返回的observable對象,而_subscribeHandler是創建序列所保存的閉包,此時我們的閉包就被調用了,被調用閉包如下:

   let obs = Observable<Any>.create { (observer) -> Disposable in
    //3、發送消息
    observer.onNext("我是一條消息")
    return Disposables.create()
}

發送信號的閉包被調用,接下來就是信號發送了。

3、發送信號

根據上面步驟繼續探索,代碼已經執行到我們的業務層。
在信號發送閉包中通常調用一下三種方法,用來發送信號。如下:

  • observer.onNext("我是一條消息") 信號發送
  • observer.onCompleted() 序列完成,完成后序列將被釋放
  • observer.onError(error) 序列出錯中斷,序列不可繼續使用,被釋放

以上三個方法為ObserverType的拓展方法

extension ObserverType {
    /// Convenience method equivalent to `on(.next(element: E))`
    ///
    /// - parameter element: Next element to send to observer(s)
    public func onNext(_ element: E) {
        self.on(.next(element))
    }
    /// Convenience method equivalent to `on(.completed)`
    public func onCompleted() {
        self.on(.completed)
    }
    /// Convenience method equivalent to `on(.error(Swift.Error))`
    /// - parameter error: Swift.Error to send to observer(s)
    public func onError(_ error: Swift.Error) {
        self.on(.error(error))
    }
}
  • E表示了一個泛型信號量,可表示任意類型的信號
  • .next(element)是一個帶泛型參數的枚舉,管理了三種類型事件的消息傳遞。如下:
public enum Event<Element> {
    /// Next element is produced.
    case next(Element)
    /// Sequence terminated with an error.
    case error(Swift.Error)
    /// Sequence completed successfully.
    case completed
}

on這是AnonymousObservableSink中的方法,代碼如下:

final private class AnonymousObservableSink<O: ObserverType>: Sink<O>, ObserverType {
    typealias E = O.E
    typealias Parent = AnonymousObservable<E>
    // 代碼省略若干行
    func on(_ event: Event<E>) {
        #if DEBUG
            self._synchronizationTracker.register(synchronizationErrorMessage: .default)
            defer { self._synchronizationTracker.unregister() }
        #endif
        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()
            }
        }
    }
}

內部根據Event枚舉不同成員變量做不同的信號發送,信號發送調用了forwardOn方法。方法實現如下:

class Sink<O : ObserverType> : Disposable {
    init(observer: O, cancel: Cancelable) {
        self._observer = observer
        self._cancel = cancel
    }

    final func forwardOn(_ event: Event<O.E>) {
        if isFlagSet(&self._disposed, 1) {
            return
        }
        self._observer.on(event)
    }
}

代碼有些長只保留了核心部分,SinkAnonymousObservableSink的父類,見上文2.7處描述_observer即是訂閱中在內部產生的AnonymousObserver對象,而該對象調用了on方法并傳遞了信號。on方法所在位置如下:

  • AnonymousObserver -> ObserverBase -> on()
class ObserverBase<ElementType> : Disposable, ObserverType {
    typealias E = ElementType
    func on(_ event: Event<E>) {
        switch event {
        case .next:
            if load(&self._isStopped) == 0 {
                self.onCore(event)
            }
        case .error, .completed:
            if fetchOr(&self._isStopped, 1) == 0 {
                self.onCore(event)
            }
        }
    }
}

在方法內部又掉用了self.onCore(event),此時該方法在AnonymousObserver中實現,代碼如下:

final class AnonymousObserver<ElementType> : ObserverBase<ElementType> {
    typealias Element = ElementType
    typealias EventHandler = (Event<Element>) -> Void
    private let _eventHandler : EventHandler
    init(_ eventHandler: @escaping EventHandler) {
        self._eventHandler = eventHandler
    }

    override func onCore(_ event: Event<Element>) {
        return self._eventHandler(event)
    }
}

源碼分析

  • 此處通過_eventHandler來發送信號,_eventHandler是從哪來的呢?逆推onCore調用者是observer,而observer是訂閱時在內部創建的,被一層層傳入到此
  • 而在observer初始化時即被保存為
    _eventHandler_eventHandler調用即調用了訂閱時創建的observer閉包,進而信號又通過閉包內的閉包傳出到業務層
//2、訂閱序列
obs.subscribe(onNext: { (val) in
    print("onNext:\(val)")
}).disposed(by: disposeBag)

天呢!容我喘口氣~~

至此我們響應式編程的創建、訂閱、發送、接收等流程就已完成。整個流程會覺得很復雜,但它統一了所有事件的創建與監聽,統一思想快速開發,今后的開發流程就是:

  • 創建序列 -> 訂閱序列 -> 發送序列 -> 響應序列

sink在Rx中充當管理者,管理序列,觀察者和銷毀者,將序列發送至觀察者,并管理銷毀者適時消耗序列,回收資源。

最后附上兩張總結圖:

Observable.png
Observable.png
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,797評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,179評論 3 414
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,628評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,642評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,444評論 6 405
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,948評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,040評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,185評論 0 287
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,717評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,602評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,794評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,316評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,045評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,418評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,671評論 1 281
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,414評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,750評論 2 370

推薦閱讀更多精彩內容

  • 在正文開始之前的最后,放上GitHub鏈接和引入依賴的gradle代碼: Github: https://gith...
    蘇蘇說zz閱讀 686評論 0 2
  • 在正文開始之前的最后,放上 GitHub 鏈接和引入依賴的 gradle 代碼: Github: https://...
    松江野人閱讀 5,928評論 0 1
  • 發現 關注 消息 RxSwift入坑解讀-你所需要知道的各種概念 沸沸騰關注 2016.11.27 19:11*字...
    楓葉1234閱讀 2,809評論 0 2
  • 今天母親節,醒來后刷屏,滿屏都是母親節祝福。我不想發朋友圈,母親不會微信,只有一部能通話的手機。她那一代人,含蓄內...
    浮蓮閱讀 580評論 3 7
  • 歐陽文修是一名汽車司機,八十年代,五一節前一天,車隊開了一次大干紅五月的動員大會。 主要講安全生產,多拉快跑,完成...
    講誠信的人閱讀 887評論 10 10