前言
在前面的基礎之上接下來我會介紹一些常用的函數和實用技巧。首先,本文將會介紹那些用于對 next 事件進行過濾的操作。這些過濾操作類似于 Swift 標準庫中的 filter 操作。它能在我們開始真正進行業務處理前先把那些不符合條件的過濾掉,而且這種函數式編程的范式也能開闊我們的思維。
Ignore 過濾
RxSwift 中最簡單直接的過濾操作就是 ignoreElements 了。該操作會屏蔽所有的 next 事件,只會將注意力放在 error 和 completed 事件上。如下圖所示,在整個生命周期中可觀察對象的所有 next 都被過濾。
示例代碼:
let strikes = PublishSubject<String>() let disposeBag = DisposeBag()strikes .ignoreElements() .subscribe { _ in print("You're out!") } .addDisposableTo(disposeBag) strikes.onNext("X")strikes.onNext("X")strikes.onNext("X") strikes.onCompleted()/* 打印結果You're out!*/
不過相比于殘暴的全部過濾,有時候我們可能只是需要過濾某些特定的事件。例如,我們可以通過 elementAt 對特定索引號 next 進行過濾。下圖演示了只響應第二個 next 事件的 elementAt 操作。
與之相應的代碼為:
let strikes = PublishSubject<String>() let disposeBag = DisposeBag() strikes .elementAt(2) .subscribe(onNext: { str in print(str) }) .addDisposableTo(disposeBag) strikes.onNext("1")strikes.onNext("2")strikes.onNext("3") strikes.onCompleted()/* 打印結果3*/
上面兩個操作最后針對的 next 事件最多只會有一個,但是大多數時候我們其實需要篩選出一組符合條件的 next 事件。下圖演示的就是使用 filter 篩選數據小于 3 的操作。
圖示對應代碼如下:
let strikes = PublishSubject<Int>() let disposeBag = DisposeBag() strikes .filter{ $0 < 3 } .subscribe(onNext: { num in print("/(num)") }) .addDisposableTo(disposeBag) strikes.onNext(1)strikes.onNext(2)strikes.onNext(3)strikes.onNext(4)strikes.onNext(5) strikes.onCompleted()/* 打印結果12*/
Skip 過濾
除了忽略操作外,另一個常見的過濾就是跳過操作了。在所有的跳過操作中,最簡單的就屬 skip 了。通過設定參數,我們就能和簡單實現跳過指定個數的事件。例如,下圖久演示跳過前兩個事件的操作。
let strikes = PublishSubject<Int>() let disposeBag = DisposeBag() strikes .skip(2) .subscribe(onNext: { num in print("/(num)") }) .addDisposableTo(disposeBag) strikes.onNext(1)strikes.onNext(2)strikes.onNext(3)strikes.onNext(4)strikes.onNext(5) strikes.onCompleted()/* 打印結果345*/
當然除了跳過指定索引號的事件之外,我們依舊通過 skipWhile 我們能夠實現類似 filter 類似的操作。只不過 filter 會過濾整個生命周期內的符合條件的事件,而 skipWhile 在找到第一個不符合跳過操作的事件之后就不再工作。例如,下圖 skipWhile 的條件是數據為奇數就跳過,但是當數據 2 執行之后 數據 3 雖然也是奇數但是不會在跳過。所以嚴格意義上來說 skipWhile 可能有點歧義,實際是它會跳過所有符合條件的事件,直到找到第一個能執行事件后就不再生效。
下面是跳過偶數的 skipWhile 代碼:
let strikes = PublishSubject<Int>() let disposeBag = DisposeBag() strikes .skipWhile{ num in num % 2 == 0 } .subscribe(onNext: { num in print("/(num)") }) .addDisposableTo(disposeBag) strikes.onNext(2)strikes.onNext(2)strikes.onNext(3)strikes.onNext(4)strikes.onNext(5) strikes.onCompleted()/* 打印結果345*/
到目前為止,上面的過濾操作都是基于一些靜態條件。如果現在你需要根據其它可觀察對象實例的行為進行過濾判斷怎么辦呢?所以接下來將會介紹涉及多實例的動態判斷,其中最常見的就是 skipUntil 操作。該操作過程如下圖,上面兩行表示可觀察對象的生命周期而最下面的表示觀察者,直到第二行的可觀察對象發送數據后第三行的觀察者才能接受到第一行發送的數據。
圖示對應代碼:
let strikes = PublishSubject<String>()let trigger = PublishSubject<String>() let disposeBag = DisposeBag() strikes .skipUntil(trigger) .subscribe(onNext: { print($0) }) .addDisposableTo(disposeBag) strikes.onNext("1")trigger.onNext("X")strikes.onNext("2")strikes.onNext("3") strikes.onCompleted()/* 打印結果23*/
Take 過濾
這是一組與 Skip 相反的過濾操作。這組操作中最基礎的操作為 take ,該操作的過程完全與 skip 相反。下圖演示了 take(2) 操作的過程,它只會對前兩個事件進行響應而忽略后面的事件。
上圖對應代碼:
let strikes = PublishSubject<String>() let disposeBag = DisposeBag() strikes .take(2) .subscribe(onNext: { print($0) }) .addDisposableTo(disposeBag) strikes.onNext("1")strikes.onNext("2")strikes.onNext("3") strikes.onCompleted()/* 打印結果12*/
除此之外,skipWhile 也有對應的 Take 操作 takeWhile ,兩者的代碼結構幾乎一致只不過前者是跳過操作而后者則是響應操作。不過這里我不準備介紹 takeWhile 操作(可以自己動手試下),而是介紹 takeWhile 變種 takeWhileWithIndex。其實函數名已經表明了該操作的主要功能,在 takeWhile 的基礎上會加上索引 index 參數。因為有時候我們除了需要通過 value 進行過濾判斷外,索引 index 也可能是一個判斷維度。下圖就展示了 takeWhileWithIndex 簡單使用示例,對于 value 和 index 值小于 1 的事件全部跳過。
圖示對應代碼:
let strikes = PublishSubject<Int>() let disposeBag = DisposeBag() strikes .takeWhileWithIndex { integer, index in integer > 1 && index > 1 } .subscribe(onNext: { print( "/($0)") }) .addDisposableTo(disposeBag) strikes.onNext(1)strikes.onNext(2)strikes.onNext(3) strikes.onCompleted()/* 打印結果3*/
其實 Skip 組中同樣存在與 takeWhileWithIndex 相對的 skipWhileWithIndex ,感興趣可以自己檢驗一下。接下來我們介紹 Take 組中的最后一個操作 takeUntil 。同樣地該操作是 skipUntil 的反操作,直到另一個實例對象觸發后該實例對象的觀察者才會停止響應。下圖就是 takeUntil 操作的一個簡單示例,作為觀察者第三行會一直響應第一行可觀察對象發送的數據,直到第二行對象觸發后才停止。
對應代碼:
let strikes = PublishSubject<String>()let trigger = PublishSubject<String>()let disposeBag = DisposeBag() strikes .takeUntil(trigger) .subscribe(onNext: { print($0) }) .addDisposableTo(disposeBag) strikes.onNext("1")strikes.onNext("2")trigger.onNext("X")strikes.onNext("3") strikes.onCompleted()/* 打印結果12*/
Distinct 過濾
最后本文將介紹 Distinct 過濾操作 distinctUntilChanged 。對于觀察者來說,有時可觀察對象可能在某段時間內連續發生相同的數據。假設這些數據與 UI 相關的話,那么這里就存在不必要的刷新操作了。所以我們有必要對過濾這些連續的相同數據,減少不必要的響應操作。下圖就是一個簡單的示例,圖中我們過濾掉了相同的后續數據,只會對第一個作出響應。
對應示例代碼:
let strikes = PublishSubject<String>()let disposeBag = DisposeBag() strikes .distinctUntilChanged() .subscribe(onNext: { print($0) }) .addDisposableTo(disposeBag) strikes.onNext("1")strikes.onNext("2")strikes.onNext("2")strikes.onNext("3") strikes.onCompleted()/* 打印結果123*/
總結
本文在前面的基礎上通過圖示和代碼介紹了主要的過濾操作。掌握好這些操作有利于我們最大化的發揮 RxSwift 功力。當然文中的代碼都非常簡單,所以我希望你在實際編程中不斷磨練。
好了,以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作能帶來一定的幫助,如果有疑問大家可以留言交流,謝謝大家對VEVB武林網的支持。
新聞熱點
疑難解答