RxSwift: SubscribeOn 與 ObserverOn 的區(qū)別

摘要


使用 subscribeOn

我們用 subscribeOn 來決定數(shù)據(jù)序列的構(gòu)建函數(shù)在哪個(gè) Scheduler 上運(yùn)行。以上例子中批狐,由于獲取 Data 需要花很長的時(shí)間,所以用 subscribeOn 切換到 后臺(tái) Scheduler 來獲取 Data。這樣可以避免主線程被阻塞。

使用 observeOn

我們用 observeOn 來決定在哪個(gè) Scheduler 監(jiān)聽這個(gè)數(shù)據(jù)序列晃虫。以上例子中,通過使用 observeOn 方法切換到主線程來監(jiān)聽并且處理結(jié)果扣墩。

一個(gè)比較典型的例子就是哲银,在后臺(tái)發(fā)起網(wǎng)絡(luò)請(qǐng)求,然后解析數(shù)據(jù)沮榜,最后在主線程刷新頁面盘榨。你就可以先用 subscribeOn 切到后臺(tái)去發(fā)送請(qǐng)求并解析數(shù)據(jù)喻粹,最后用 observeOn 切換到主線程更新頁面

結(jié)構(gòu)


在討論 SubscribeOnObserverOn 的區(qū)別之前蟆融,先來討論一下 Observable 從產(chǎn)生事件到響應(yīng)事件的結(jié)構(gòu),可以分為三部分:

  1. 產(chǎn)生事件: Observable<Int>.create(...)
  2. 操作事件: map(),filter(), zip() 等操作符的功能
  3. 響應(yīng)事件:subscribe(onNext: ..., onCompleted: ..., onError: ...)
        Observable<Int>.create { observer in
                1 ..... 產(chǎn)生事件
            }
            .map { element -> String in
                2 ...... 操作事件
            }
            .subscribe(onNext: { element in
                3 ...... 響應(yīng)事件
            }).disposed(by: disposeBag)

1. 默認(rèn)情況

在沒有使用 SubscribeOnObserverOn 明確指定在哪個(gè)隊(duì)列中調(diào)度時(shí)守呜,subscribe()在哪個(gè)隊(duì)列被調(diào)用型酥,「產(chǎn)生事件」和「響應(yīng)事件」的方法就在哪個(gè)隊(duì)列中執(zhí)行

在「子線程」中調(diào)用 subscribe()
    func invokeSubscribeInGlobalQueue() {
        let observableInt = Observable<Int>.create { observer in
            print("產(chǎn)生事件 -> \(self.currentQueueName() ?? "queue")")
            observer.onNext(1)
            return Disposables.create()
            }
            .map {  element -> Int in
                print("操作事件1 -> \(self.currentQueueName() ?? "queue")")
                return element + 1
            }
            .map { element -> Int in
                print("操作事件2 -> \(self.currentQueueName() ?? "queue")")
                return element + 1
        }

        DispatchQueue.global().async {
            print("調(diào)用 subscribe() 的隊(duì)列: \(self.currentQueueName() ?? "queue")")
            observableInt.subscribe(onNext: { element in
                print("響應(yīng)事件 -> \(self.currentQueueName() ?? "queue"), element -> \(element)\n\n")
            }).disposed(by: self.disposeBag)
        }
    }

輸出結(jié)果:

調(diào)用 subscribe() 的隊(duì)列: com.apple.root.default-qos
產(chǎn)生事件 -> com.apple.root.default-qos
操作事件1 -> com.apple.root.default-qos
操作事件2 -> com.apple.root.default-qos
響應(yīng)事件 -> com.apple.root.default-qos, element -> 3

在「主線程」中調(diào)用 subscribe()
 func invokeSubscribeInMainQueue() {
        let observableInt = Observable<Int>.create { observer in
            print("產(chǎn)生事件 -> \(self.currentQueueName() ?? "queue")")
            observer.onNext(1)
            return Disposables.create()
            }
            .map {  element -> Int in
                print("操作事件1 -> \(self.currentQueueName() ?? "queue")")
                return element + 1
            }
            .map { element -> Int in
                print("操作事件2 -> \(self.currentQueueName() ?? "queue")")
                return element + 1
        }
        
        print("調(diào)用 subscribe() 的隊(duì)列: \(self.currentQueueName() ?? "queue")")
        observableInt.subscribe(onNext: { element in
            print("響應(yīng)事件 -> \(self.currentQueueName() ?? "queue"), element -> \(element)\n\n")
        }).disposed(by: self.disposeBag)
    }

輸出結(jié)果:

調(diào)用 subscribe() 的隊(duì)列: com.apple.main-thread
產(chǎn)生事件 -> com.apple.main-thread
操作事件1 -> com.apple.main-thread
操作事件2 -> com.apple.main-thread
響應(yīng)事件 -> com.apple.main-thread, element -> 3

2. 只使用 SubscribeOn 指定「產(chǎn)生事件」執(zhí)行的隊(duì)列

SubscribeOn 是向上和向下作用的,只使用subscribeOn指定執(zhí)行的隊(duì)列之后查乒,「產(chǎn)生事件」弥喉、「操作事件」、「響應(yīng)事件」都將在指定的隊(duì)列中執(zhí)行玛迄。

    func subscribeOn() {
        Observable<Int>.create { observer in
            print("產(chǎn)生事件 -> \(self.currentQueueName() ?? "queue")")
            observer.onNext(1)
            return Disposables.create()
            }
            .map {  element -> Int in
                print("操作事件1 -> \(self.currentQueueName() ?? "queue")")
                return element + 1
            }
            .subscribeOn(SerialDispatchQueueScheduler(qos: .background))
            .map { element -> Int in
                print("操作事件2 -> \(self.currentQueueName() ?? "queue")")
                return element + 1
            }
            .subscribe(onNext: { element in
                print("響應(yīng)事件 -> \(self.currentQueueName() ?? "queue"), element -> \(element)\n\n")
            }).disposed(by: self.disposeBag)
    }

輸出結(jié)果:

產(chǎn)生事件 -> rx.global_dispatch_queue.serial
操作事件1 -> rx.global_dispatch_queue.serial
操作事件2 -> rx.global_dispatch_queue.serial
響應(yīng)事件 -> rx.global_dispatch_queue.serial, element -> 3

當(dāng)出現(xiàn)多個(gè) subscribeOn的時(shí)候由境,只有第一個(gè)能起到作用。

    func subscribeOn() {
        Observable<Int>.create { observer in
            print("產(chǎn)生事件 -> \(self.currentQueueName() ?? "queue")")
            observer.onNext(1)
            return Disposables.create()
            }
            .map {  element -> Int in
                print("操作事件1 -> \(self.currentQueueName() ?? "queue")")
                return element + 1
            }
            .subscribeOn(SerialDispatchQueueScheduler(qos: .background))
            .map { element -> Int in
                print("操作事件2 -> \(self.currentQueueName() ?? "queue")")
                return element + 1
            }
            .subscribeOn(MainScheduler.instance)
            .subscribe(onNext: { element in
                print("響應(yīng)事件 -> \(self.currentQueueName() ?? "queue"), element -> \(element)\n\n")
            }).disposed(by: self.disposeBag)
    }

輸出結(jié)果:

產(chǎn)生事件 -> rx.global_dispatch_queue.serial
操作事件1 -> rx.global_dispatch_queue.serial
操作事件2 -> rx.global_dispatch_queue.serial
響應(yīng)事件 -> rx.global_dispatch_queue.serial, element -> 3

3. 只使用 ObserverOn 指定「響應(yīng)事件」執(zhí)行的隊(duì)列

observarOn是向下作用的, observarOn 可以指定其后面的「操作事件」和「響應(yīng)事件」執(zhí)行的隊(duì)列,可以使用多個(gè)observarOn來改變不同的「操作事件」執(zhí)行的隊(duì)列

   func observerOn() {
        Observable<Int>.create { observer in
            print("產(chǎn)生事件 -> \(self.currentQueueName() ?? "queue")")
            observer.onNext(1)
            return Disposables.create()
            }
            .map {  element -> Int in
                print("操作事件1 -> \(self.currentQueueName() ?? "queue")")
                return element + 1
            }
            .observeOn(SerialDispatchQueueScheduler(qos: .background))
            .map { element -> Int in
                print("操作事件2 -> \(self.currentQueueName() ?? "queue")")
                return element + 1
            }
            .observeOn(MainScheduler.instance)
            .map { element -> Int in
                print("操作事件3 -> \(self.currentQueueName() ?? "queue")")
                return element + 1
            }
            .observeOn(SerialDispatchQueueScheduler(qos: .background))
            .map { element -> Int in
                print("操作事件4 -> \(self.currentQueueName() ?? "queue")")
                return element + 1
            }
            .observeOn(MainScheduler.instance)
            .observeOn(SerialDispatchQueueScheduler(qos: .background))
            .subscribe(onNext: { element in
                print("響應(yīng)事件 -> \(self.currentQueueName() ?? "queue"), element -> \(element) \n\n")
            }).disposed(by: disposeBag)
    }

輸出結(jié)果:

產(chǎn)生事件 -> com.apple.main-thread
操作事件1 -> com.apple.main-thread
操作事件2 -> rx.global_dispatch_queue.serial
操作事件3 -> com.apple.main-thread
操作事件4 -> rx.global_dispatch_queue.serial
響應(yīng)事件 -> rx.global_dispatch_queue.serial, element -> 5

4. 同時(shí)使用 SubscribeOn 和 ObserverOn

同時(shí)使用 SubscribeOnObserverOn時(shí)虏杰〖ン。「產(chǎn)生事件」和 ObserveOn 之前的 「操作事件」將會(huì)在 SubscribeOn 指定的隊(duì)列中執(zhí)行。ObserveOn 之后的 「操作事件」和 「響應(yīng)事件」將會(huì)在 ObserveOn 指定的隊(duì)列中執(zhí)行纺阔。

SubscribeOnObserveOn 在代碼中出現(xiàn)的順序不會(huì)影響上述的邏輯

    func subscribeOnAndObserveOn() {
        Observable<Int>.create { observer in
            print("產(chǎn)生事件 -> \(self.currentQueueName() ?? "queue")")
            observer.onNext(1)
            return Disposables.create()
            }
            
            .map {  element -> Int in
                print("操作事件1 -> \(self.currentQueueName() ?? "queue")")
                return element + 1
            }
            .observeOn(MainScheduler.instance)
            .subscribeOn(SerialDispatchQueueScheduler(qos: .background))
            .map { element -> Int in
                print("操作事件2 -> \(self.currentQueueName() ?? "queue")")
                return element + 1
            }
            .subscribe(onNext: { element in
                print("響應(yīng)事件 -> \(self.currentQueueName() ?? "queue"), element -> \(element)\n\n")
            }).disposed(by: self.disposeBag)
    }

輸出結(jié)果:

產(chǎn)生事件 -> rx.global_dispatch_queue.serial
操作事件1 -> rx.global_dispatch_queue.serial
操作事件2 -> com.apple.main-thread
響應(yīng)事件 -> com.apple.main-thread, element -> 3

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末瘸彤,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子笛钝,更是在濱河造成了極大的恐慌质况,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,548評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件玻靡,死亡現(xiàn)場(chǎng)離奇詭異结榄,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)囤捻,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,497評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門潭陪,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人最蕾,你說我怎么就攤上這事依溯。” “怎么了瘟则?”我有些...
    開封第一講書人閱讀 167,990評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵黎炉,是天一觀的道長。 經(jīng)常有香客問我醋拧,道長慷嗜,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,618評(píng)論 1 296
  • 正文 為了忘掉前任丹壕,我火速辦了婚禮庆械,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘菌赖。我一直安慰自己缭乘,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,618評(píng)論 6 397
  • 文/花漫 我一把揭開白布琉用。 她就那樣靜靜地躺著堕绩,像睡著了一般。 火紅的嫁衣襯著肌膚如雪邑时。 梳的紋絲不亂的頭發(fā)上奴紧,一...
    開封第一講書人閱讀 52,246評(píng)論 1 308
  • 那天,我揣著相機(jī)與錄音晶丘,去河邊找鬼黍氮。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的沫浆。 我是一名探鬼主播觉壶,決...
    沈念sama閱讀 40,819評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼件缸!你這毒婦竟也來了铜靶?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,725評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤他炊,失蹤者是張志新(化名)和其女友劉穎争剿,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體痊末,經(jīng)...
    沈念sama閱讀 46,268評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡蚕苇,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,356評(píng)論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了凿叠。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片涩笤。...
    茶點(diǎn)故事閱讀 40,488評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖盒件,靈堂內(nèi)的尸體忽然破棺而出蹬碧,到底是詐尸還是另有隱情,我是刑警寧澤炒刁,帶...
    沈念sama閱讀 36,181評(píng)論 5 350
  • 正文 年R本政府宣布恩沽,位于F島的核電站,受9級(jí)特大地震影響翔始,放射性物質(zhì)發(fā)生泄漏罗心。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,862評(píng)論 3 333
  • 文/蒙蒙 一城瞎、第九天 我趴在偏房一處隱蔽的房頂上張望渤闷。 院中可真熱鬧,春花似錦脖镀、人聲如沸飒箭。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,331評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽补憾。三九已至漫萄,卻和暖如春卷员,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背腾务。 一陣腳步聲響...
    開封第一講書人閱讀 33,445評(píng)論 1 272
  • 我被黑心中介騙來泰國打工毕骡, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,897評(píng)論 3 376
  • 正文 我出身青樓未巫,卻偏偏與公主長得像窿撬,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子叙凡,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,500評(píng)論 2 359