RxSwift使用技巧之過(guò)濾操作詳解
前言
在前面的基礎(chǔ)之上接下來(lái)我會(huì)介紹一些常用的函數(shù)和實(shí)用技巧。首先,本文將會(huì)介紹那些用于對(duì) next 事件進(jìn)行過(guò)濾的操作。這些過(guò)濾操作類(lèi)似于 Swift 標(biāo)準(zhǔn)庫(kù)中的 filter 操作。它能在我們開(kāi)始真正進(jìn)行業(yè)務(wù)處理前先把那些不符合條件的過(guò)濾掉,而且這種函數(shù)式編程的范式也能開(kāi)闊我們的思維。
Ignore 過(guò)濾
RxSwift 中最簡(jiǎn)單直接的過(guò)濾操作就是 ignoreElements 了。該操作會(huì)屏蔽所有的 next 事件,只會(huì)將注意力放在 error 和 completed 事件上。如下圖所示,在整個(gè)生命周期中可觀察對(duì)象的所有 next 都被過(guò)濾。
示例代碼:
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() /* 打印結(jié)果 You're out! */
不過(guò)相比于殘暴的全部過(guò)濾,有時(shí)候我們可能只是需要過(guò)濾某些特定的事件。例如,我們可以通過(guò) elementAt 對(duì)特定索引號(hào) next 進(jìn)行過(guò)濾。下圖演示了只響應(yīng)第二個(gè) next 事件的 elementAt 操作。
與之相應(yīng)的代碼為:
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() /* 打印結(jié)果 3 */
上面兩個(gè)操作最后針對(duì)的 next 事件最多只會(huì)有一個(gè),但是大多數(shù)時(shí)候我們其實(shí)需要篩選出一組符合條件的 next 事件。下圖演示的就是使用 filter 篩選數(shù)據(jù)小于 3 的操作。
圖示對(duì)應(yīng)代碼如下:
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() /* 打印結(jié)果 1 2 */
Skip 過(guò)濾
除了忽略操作外,另一個(gè)常見(jiàn)的過(guò)濾就是跳過(guò)操作了。在所有的跳過(guò)操作中,最簡(jiǎn)單的就屬 skip 了。通過(guò)設(shè)定參數(shù),我們就能和簡(jiǎn)單實(shí)現(xiàn)跳過(guò)指定個(gè)數(shù)的事件。例如,下圖久演示跳過(guò)前兩個(gè)事件的操作。
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() /* 打印結(jié)果 3 4 5 */
當(dāng)然除了跳過(guò)指定索引號(hào)的事件之外,我們依舊通過(guò) skipWhile 我們能夠?qū)崿F(xiàn)類(lèi)似 filter 類(lèi)似的操作。只不過(guò) filter 會(huì)過(guò)濾整個(gè)生命周期內(nèi)的符合條件的事件,而 skipWhile 在找到第一個(gè)不符合跳過(guò)操作的事件之后就不再工作。例如,下圖 skipWhile 的條件是數(shù)據(jù)為奇數(shù)就跳過(guò),但是當(dāng)數(shù)據(jù) 2 執(zhí)行之后 數(shù)據(jù) 3 雖然也是奇數(shù)但是不會(huì)在跳過(guò)。所以嚴(yán)格意義上來(lái)說(shuō) skipWhile 可能有點(diǎn)歧義,實(shí)際是它會(huì)跳過(guò)所有符合條件的事件,直到找到第一個(gè)能執(zhí)行事件后就不再生效。
下面是跳過(guò)偶數(shù)的 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() /* 打印結(jié)果 3 4 5 */
到目前為止,上面的過(guò)濾操作都是基于一些靜態(tài)條件。如果現(xiàn)在你需要根據(jù)其它可觀察對(duì)象實(shí)例的行為進(jìn)行過(guò)濾判斷怎么辦呢?所以接下來(lái)將會(huì)介紹涉及多實(shí)例的動(dòng)態(tài)判斷,其中最常見(jiàn)的就是 skipUntil 操作。該操作過(guò)程如下圖,上面兩行表示可觀察對(duì)象的生命周期而最下面的表示觀察者,直到第二行的可觀察對(duì)象發(fā)送數(shù)據(jù)后第三行的觀察者才能接受到第一行發(fā)送的數(shù)據(jù)。
圖示對(duì)應(yīng)代碼:
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() /* 打印結(jié)果 2 3 */
Take 過(guò)濾
這是一組與 Skip 相反的過(guò)濾操作。這組操作中最基礎(chǔ)的操作為 take ,該操作的過(guò)程完全與 skip 相反。下圖演示了 take(2) 操作的過(guò)程,它只會(huì)對(duì)前兩個(gè)事件進(jìn)行響應(yīng)而忽略后面的事件。
上圖對(duì)應(yīng)代碼:
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() /* 打印結(jié)果 1 2 */
除此之外,skipWhile 也有對(duì)應(yīng)的 Take 操作 takeWhile ,兩者的代碼結(jié)構(gòu)幾乎一致只不過(guò)前者是跳過(guò)操作而后者則是響應(yīng)操作。不過(guò)這里我不準(zhǔn)備介紹 takeWhile 操作(可以自己動(dòng)手試下),而是介紹 takeWhile 變種 takeWhileWithIndex。其實(shí)函數(shù)名已經(jīng)表明了該操作的主要功能,在 takeWhile 的基礎(chǔ)上會(huì)加上索引 index 參數(shù)。因?yàn)橛袝r(shí)候我們除了需要通過(guò) value 進(jìn)行過(guò)濾判斷外,索引 index 也可能是一個(gè)判斷維度。下圖就展示了 takeWhileWithIndex 簡(jiǎn)單使用示例,對(duì)于 value 和 index 值小于 1 的事件全部跳過(guò)。
圖示對(duì)應(yīng)代碼:
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() /* 打印結(jié)果 3 */
其實(shí) Skip 組中同樣存在與 takeWhileWithIndex 相對(duì)的 skipWhileWithIndex ,感興趣可以自己檢驗(yàn)一下。接下來(lái)我們介紹 Take 組中的最后一個(gè)操作 takeUntil 。同樣地該操作是 skipUntil 的反操作,直到另一個(gè)實(shí)例對(duì)象觸發(fā)后該實(shí)例對(duì)象的觀察者才會(huì)停止響應(yīng)。下圖就是 takeUntil 操作的一個(gè)簡(jiǎn)單示例,作為觀察者第三行會(huì)一直響應(yīng)第一行可觀察對(duì)象發(fā)送的數(shù)據(jù),直到第二行對(duì)象觸發(fā)后才停止。
對(duì)應(yīng)代碼:
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() /* 打印結(jié)果 1 2 */
Distinct 過(guò)濾
最后本文將介紹 Distinct 過(guò)濾操作 distinctUntilChanged 。對(duì)于觀察者來(lái)說(shuō),有時(shí)可觀察對(duì)象可能在某段時(shí)間內(nèi)連續(xù)發(fā)生相同的數(shù)據(jù)。假設(shè)這些數(shù)據(jù)與 UI 相關(guān)的話,那么這里就存在不必要的刷新操作了。所以我們有必要對(duì)過(guò)濾這些連續(xù)的相同數(shù)據(jù),減少不必要的響應(yīng)操作。下圖就是一個(gè)簡(jiǎn)單的示例,圖中我們過(guò)濾掉了相同的后續(xù)數(shù)據(jù),只會(huì)對(duì)第一個(gè)作出響應(yīng)。
對(duì)應(yīng)示例代碼:
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() /* 打印結(jié)果 1 2 3 */
總結(jié)
本文在前面的基礎(chǔ)上通過(guò)圖示和代碼介紹了主要的過(guò)濾操作。掌握好這些操作有利于我們最大化的發(fā)揮 RxSwift 功力。當(dāng)然文中的代碼都非常簡(jiǎn)單,所以我希望你在實(shí)際編程中不斷磨練。
好了,以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作能帶來(lái)一定的幫助,如果有疑問(wèn)大家可以留言交流,謝謝大家對(duì)腳本之家的支持。
相關(guān)文章
swift指針及內(nèi)存管理內(nèi)存綁定實(shí)例詳解
這篇文章主要為大家介紹了swift指針及內(nèi)存管理內(nèi)存綁定實(shí)例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-11-11Swift中的可選項(xiàng)Optional解包方式實(shí)現(xiàn)原理
這篇文章主要為大家介紹了Swift中的可選項(xiàng)Optional解包方式實(shí)現(xiàn)原理示例分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-03-03Swift中通知中心(NotificationCenter)的使用示例
這篇文章主要給大家介紹了關(guān)于Swift中通知中心(NotificationCenter)使用的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧。2017-10-10Swift類(lèi)型創(chuàng)建之自定義一個(gè)類(lèi)型詳解
這篇文章主要介紹了Swift類(lèi)型創(chuàng)建之自定義一個(gè)類(lèi)型詳解,本文講解了自定義原型、實(shí)現(xiàn)默認(rèn)值、支持基本布爾型初始化、支持Bool類(lèi)型判斷、支持兼容各們各派的類(lèi)型、完善OCBool的布爾基因體系等內(nèi)容,需要的朋友可以參考下2015-05-05iOS Swift讀取本地json文件報(bào)錯(cuò)的解決方法
只要是app開(kāi)發(fā)者都知道,從服務(wù)器端獲得的數(shù)據(jù)要不就是json格式的數(shù)據(jù),要么就是xml格式的數(shù)據(jù),而這篇文章主要給大家介紹了關(guān)于iOS Swift讀取本地json文件報(bào)錯(cuò)的解決方法,需要的朋友可以參考借鑒,下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧。2017-11-11