RxSwift 入坑解讀-那些難以理解的細節

發表於2016-12-27

上一篇文章RxSwift入坑記-各種概念解讀內容比較多,文章簡直是太長了,我都難以堅持看下去?,建議大家粗略讀一遍就行了,用到的時候來查一下,慢慢地就掌握了。

這篇文章接著上篇文章,主要來深入瞭解一些RxSwift實戰中用到的一些重要知識點,這裡面有很多自己的理解和思考,包含很多網上幾乎收不到的內容,希望會是大家研究官方例子的一個重要參考資料,文章中不免會有些錯誤的地方,也請大家能多多留言交流,一起成長。這兩篇文章過後,準備寫實戰教程,希望大家多多關注吧。還有文章在我部落格裡閱讀更有感覺哦。let’s go!

Rx系列的核心就是Observable Sequence這個相信大家心中已經有所瞭解了,這裡不再囉嗦了,建議大家看看我都上一篇文章去了解一下。

Disposing

當監聽一個事件序列的時候,有訊息事件來了,我們做某些事情。但是這個事件序列不再發出訊息了,我們的監聽也就沒有什麼存在價值了,所以我們需要釋放我們這些監聽資源,其實也就是每種程式語言中的記憶體資源釋放。OC和Swift中也一樣,在你不需要用某些變數的時候,你需要把這些變數所佔用的記憶體空間釋放掉。

釋放某一個監聽的時候我們可以手動呼叫釋放方法,但是這個貌似一般不常用:

比如上面這個例子,我們建立了一個subscription監聽,在兩秒以後我們不需要了,手動呼叫dispose()方法,就能釋放監聽資源,不再列印資訊。上面的subscription不倫是在哪個執行緒中監聽,就算在主執行緒中呼叫的dispose()方法一樣會銷燬資源。

Dispose Bags

除了上面手動的方法,還有一種是自動的方式,推薦大家使用這種方式,這種方式就好像iOS中的ARC方式似得,會自動去釋放資源。

如上個例子,我們建立一個disposeBag來盛放我們需要管理的資源,然後把新建的監聽都放進去,會在適當的時候銷燬這些資源。如果你需要立即釋放資源只需要新建一個DisposeBag(),那麼上一個DisposeBag就會被銷燬。

Scheduler

這個東西其實就是執行緒,當你監聽一個事件序列的時候,會預設發生在當前執行緒,並且事件發出和事件處理都是在一個執行緒中完成,除非你中間更改了執行緒。這些東西我感覺沒必要做過多講解,用的時候查一下就好。

CurrentThreadScheduler

這是一個序列(Serial)佇列,也是預設執行緒

MainScheduler

這是主執行緒,也是一個序列佇列

SerialDispatchQueueScheduler

這是GCD中的序列佇列

ConcurrentDispatchQueueScheduler

這是GCD中的併發佇列

OperationQueueScheduler

這是一個NSOperationQueue併發佇列

如果你從併發佇列中轉到序列執行緒中,RxSwift也會把訊息變成序列訊息佇列。但是不建議從序列轉為併發。

observeOn()和subscribeOn()

這兩個東西可能很多人看官方文件說的一頭霧水,就知道最好多用observeOn(),但說明不了為啥。下面我們們就談談這倆貨到底有啥區別。

區別其實我感覺其實就一句話,subscribeOn()設定起點在哪個執行緒,observeOn()設定了後續工作在哪個執行緒。例如:

  1. 所有動作都發生在當前的預設執行緒
  2. observeOn轉換執行緒到主執行緒,下面所有的操作都是在主執行緒中
  3. subscribeOn規定動作一開始不是發生在預設執行緒了,而是在OtherScheduler了。
  4. 如果我們之前沒有呼叫observeOn,那麼這邊會在OtherScheduler發生,但是我們前面呼叫了observeOn,所以這個動作還是會在主執行緒中呼叫。

總結一下:subscribeOn只是影響事件鏈開始預設的執行緒,而observeOn規定了下一步動作發生在哪個執行緒中。

shareReplay

可能你看官方demo的時候,會有迷惑,為啥很多序列後面會有shareReplay(1)呢?,想的頭昏腦脹的。
請先看下面例子:

大家發現沒,map函式執行了兩遍,但是有些時候我不需要map函式裡的東西執行兩遍,比如map函式裡面如果執行的是網路請求,我只需要一次請求結果供大家使用就行了,多餘的請求沒啥用,浪費時間。所以這時候就需要shareReplay(1)了。這裡面的數字一般都是1,只執行一次。你可以改為2,3看看結果有啥不同哦。

自定義operator

自定義操作符很簡單,官方推薦儘量用標準的操作符,但是你也可以自定義自己的操作符,文件上說有兩種方法,這裡我們只說一下最常用的一種方法。

例如我們自定義一個map操作符:

引數是一個閉包,其中閉包引數是E型別返回值是R型別,map函式的返回值是一個Observable型別。

Driver

Driver是啥東東?Driver功能很吊,講解Driver之前我們現在看看下面的例子。

  • 首先建立一個可監聽序列results,其中flatMapLatest怎麼用我們下面講
  • 然後將results繫結到resultCount.rx.text上
  • 將results繫結到resultsTableView上

上面程式會有下面幾個異常情況

  1. 如果上面fetchAutoCompleteItems出錯了,那麼他繫結的UI將不再收到任何事件訊息
  2. 如果上面fetchAutoCompleteItems是在後臺某個執行緒中執行的,那麼事件繫結也是發生在後臺某個執行緒,這樣更新UI的時候會造成crash
  3. 有兩次繫結fetchAutoCompleteItems會執行兩次

當然針對上面問題我們也有解決方案,我們可以使用神器shareReplay(1)保證不會執行兩次,可以使用observeOn()保證後面所有操作在主執行緒完成。

但是你也可以使用Driver

drive方法只能在Driver序列中使用,Driver有以下特點:1 Driver序列不允許發出error,2 Driver序列的監聽只會在主執行緒中。所以Driver是轉為UI繫結量身打造的東西。以下情況你可以使用Driver替換BindTo:

  1. 不能發出error
  2. 在主執行緒中監聽
  3. 共享事件流

map和flatMap何時使用

大家看官方Demo的時候,可能會迷惑為啥有的地方使用flatMapLatest為啥有些地方使用map呢?比如上面那個Driver所用的例子。

map函式,接受一個R型別的序列,返回一個R型別的序列,還是原來的序列

flatMap函式,接收一個O型別的序列,返回一個O.E型別的序列,也就是有原來序列裡元素組成的新序列。

其實這裡的map和flatMap在swift中的作用是一樣的。map函式可以對原有序列裡面的事件元素進行改造,返回的還是原來的序列。而flatMap對原有序列中的元素進行改造和處理,每一個元素返回一個新的sequence,然後把每一個元素對應的sequence合併為一個新的sequence序列。

看下面例子:

我們使用map對序列中每一個元素進行了處理,返回的是一個元素,而使用flatMap需要返回的序列。那麼使用map也返回一個序列看看。

看到結果會列印出每一個序列,下面我們使用merge()方法將這幾個序列進行合併

合併為一個新序列後我們就可以正常列印元素了。下面看看使用faltMap()函式幹這件事

看下對比是不是一樣,這樣子對比就清晰了吧。

  • map函式只能返回原來的那一個序列,裡面的引數的返回值被當做原來序列中所對應的元素。
  • flatMap函式返回的是一個新的序列,將原來元素進行了處理,返回這些處理後的元素組成的新序列
  • map函式 + 合併函式 = flatMap函式

flatMap函式在實際應用中有很多地方需要用到,比如網路請求,網路請求可能會發生錯誤,我們需要對這個請求過程進行監聽,然後處理錯誤。只要繼續他返回的是一個新的序列。

flatMapLatest其實就是flatMap的另一個方式,只傳送最後一個合進來的序列事件。上面認證username是一個網路請求,我們需要對這個過程進行處理。

這個password不需要後臺聯網認證,只需要返回password符合不符合要求就行了,還是原來的序列就行了。

flatMap也解決了內嵌多個subscribe的問題,官方不建議內嵌多個subscribe。比如:

改寫為flatMap

好了,相信大家對這倆貨有了一個清晰的認識了吧。

UIBindingObserver

UIBindingObserver這個東西很有用的,建立我們自己的監聽者,有時候RxCocoa(RxSwiftz中對UIKit的一個擴充套件庫)給的擴充套件不夠我們使用,比如一個UITextField有個isEnabled屬性,我想把這個isEnabled變為一個observer,我們可以這樣做:

UIBindingObserver是一個類,他的初始化方法中,有兩個引數,第一個引數是一個元素本身,第一個引數是一個閉包,閉包引數是元素本身,還有他的一個屬性。

自定義了一個inputEnabled Observer裡面關聯的UITextField的isEnabled屬性。

好了,文章到這裡也差不多了,這篇文章中沒有實戰教程,但絕對都是乾貨,也許在你專研官方demo的時候看不懂某個寫法,看了這篇文章你就會豁然開朗了呢??

下一篇文章準備帶大家一起實戰,大家做好準備!!?

小夥伴們如果感覺文章可以,可以關注博主部落格

小夥伴們也可以關注博主微博,探索博主內心世界?

如要轉載請註明出處。

相關文章