RxSwift使用技巧之過濾操作詳解
前言
在前面的基礎(chǔ)之上接下來我會(huì)介紹一些常用的函數(shù)和實(shí)用技巧。首先,本文將會(huì)介紹那些用于對 next 事件進(jìn)行過濾的操作。這些過濾操作類似于 Swift 標(biāo)準(zhǔn)庫中的 filter 操作。它能在我們開始真正進(jìn)行業(yè)務(wù)處理前先把那些不符合條件的過濾掉,而且這種函數(shù)式編程的范式也能開闊我們的思維。
Ignore 過濾
RxSwift 中最簡單直接的過濾操作就是 ignoreElements 了。該操作會(huì)屏蔽所有的 next 事件,只會(huì)將注意力放在 error 和 completed 事件上。如下圖所示,在整個(gè)生命周期中可觀察對象的所有 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()
/* 打印結(jié)果
You're out!
*/
不過相比于殘暴的全部過濾,有時(shí)候我們可能只是需要過濾某些特定的事件。例如,我們可以通過 elementAt 對特定索引號 next 進(jìn)行過濾。下圖演示了只響應(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è)操作最后針對的 next 事件最多只會(huì)有一個(gè),但是大多數(shù)時(shí)候我們其實(shí)需要篩選出一組符合條件的 next 事件。下圖演示的就是使用 filter 篩選數(shù)據(jù)小于 3 的操作。

圖示對應(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 過濾
除了忽略操作外,另一個(gè)常見的過濾就是跳過操作了。在所有的跳過操作中,最簡單的就屬 skip 了。通過設(shè)定參數(shù),我們就能和簡單實(shí)現(xiàn)跳過指定個(gè)數(shù)的事件。例如,下圖久演示跳過前兩個(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)然除了跳過指定索引號的事件之外,我們依舊通過 skipWhile 我們能夠?qū)崿F(xiàn)類似 filter 類似的操作。只不過 filter 會(huì)過濾整個(gè)生命周期內(nèi)的符合條件的事件,而 skipWhile 在找到第一個(gè)不符合跳過操作的事件之后就不再工作。例如,下圖 skipWhile 的條件是數(shù)據(jù)為奇數(shù)就跳過,但是當(dāng)數(shù)據(jù) 2 執(zhí)行之后 數(shù)據(jù) 3 雖然也是奇數(shù)但是不會(huì)在跳過。所以嚴(yán)格意義上來說 skipWhile 可能有點(diǎn)歧義,實(shí)際是它會(huì)跳過所有符合條件的事件,直到找到第一個(gè)能執(zhí)行事件后就不再生效。

下面是跳過偶數(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
*/
到目前為止,上面的過濾操作都是基于一些靜態(tài)條件。如果現(xiàn)在你需要根據(jù)其它可觀察對象實(shí)例的行為進(jìn)行過濾判斷怎么辦呢?所以接下來將會(huì)介紹涉及多實(shí)例的動(dòng)態(tài)判斷,其中最常見的就是 skipUntil 操作。該操作過程如下圖,上面兩行表示可觀察對象的生命周期而最下面的表示觀察者,直到第二行的可觀察對象發(fā)送數(shù)據(jù)后第三行的觀察者才能接受到第一行發(fā)送的數(shù)據(jù)。

圖示對應(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 過濾
這是一組與 Skip 相反的過濾操作。這組操作中最基礎(chǔ)的操作為 take ,該操作的過程完全與 skip 相反。下圖演示了 take(2) 操作的過程,它只會(huì)對前兩個(gè)事件進(jìn)行響應(yīng)而忽略后面的事件。

上圖對應(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 也有對應(yīng)的 Take 操作 takeWhile ,兩者的代碼結(jié)構(gòu)幾乎一致只不過前者是跳過操作而后者則是響應(yīng)操作。不過這里我不準(zhǔn)備介紹 takeWhile 操作(可以自己動(dòng)手試下),而是介紹 takeWhile 變種 takeWhileWithIndex。其實(shí)函數(shù)名已經(jīng)表明了該操作的主要功能,在 takeWhile 的基礎(chǔ)上會(huì)加上索引 index 參數(shù)。因?yàn)橛袝r(shí)候我們除了需要通過 value 進(jìn)行過濾判斷外,索引 index 也可能是一個(gè)判斷維度。下圖就展示了 takeWhileWithIndex 簡單使用示例,對于 value 和 index 值小于 1 的事件全部跳過。

圖示對應(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 相對的 skipWhileWithIndex ,感興趣可以自己檢驗(yàn)一下。接下來我們介紹 Take 組中的最后一個(gè)操作 takeUntil 。同樣地該操作是 skipUntil 的反操作,直到另一個(gè)實(shí)例對象觸發(fā)后該實(shí)例對象的觀察者才會(huì)停止響應(yīng)。下圖就是 takeUntil 操作的一個(gè)簡單示例,作為觀察者第三行會(huì)一直響應(yīng)第一行可觀察對象發(fā)送的數(shù)據(jù),直到第二行對象觸發(fā)后才停止。



對應(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 過濾
最后本文將介紹 Distinct 過濾操作 distinctUntilChanged 。對于觀察者來說,有時(shí)可觀察對象可能在某段時(shí)間內(nèi)連續(xù)發(fā)生相同的數(shù)據(jù)。假設(shè)這些數(shù)據(jù)與 UI 相關(guān)的話,那么這里就存在不必要的刷新操作了。所以我們有必要對過濾這些連續(xù)的相同數(shù)據(jù),減少不必要的響應(yīng)操作。下圖就是一個(gè)簡單的示例,圖中我們過濾掉了相同的后續(xù)數(shù)據(jù),只會(huì)對第一個(gè)作出響應(yīng)。

對應(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ǔ)上通過圖示和代碼介紹了主要的過濾操作。掌握好這些操作有利于我們最大化的發(fā)揮 RxSwift 功力。當(dāng)然文中的代碼都非常簡單,所以我希望你在實(shí)際編程中不斷磨練。
好了,以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作能帶來一定的幫助,如果有疑問大家可以留言交流,謝謝大家對腳本之家的支持。
相關(guān)文章
Swift并發(fā)系統(tǒng)并行運(yùn)行多個(gè)任務(wù)使用詳解
這篇文章主要為大家介紹了Swift并發(fā)系統(tǒng)并行運(yùn)行多個(gè)任務(wù)使用詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-06-06
Swift中static和class關(guān)鍵字的深入講解
這篇文章主要給大家介紹了關(guān)于Swift中static和class關(guān)鍵字的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者使用Java具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧2019-03-03
簡陋的swift carthage copy-frameworks 輔助腳本代碼
下面小編就為大家分享一篇簡陋的swift carthage copy-frameworks 輔助腳本代碼,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-01-01
深入理解Swift中單例模式的替換及Swift 3.0單例模式的實(shí)現(xiàn)
這篇文章主要給大家介紹了關(guān)于Swift中單例模式替換的相關(guān)資料,然后又跟大家分享了關(guān)于Swift3.0 單例模式實(shí)現(xiàn)的幾種方法-Dispatch_Once的內(nèi)容,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考借鑒,下面來一起看看吧。2017-11-11
Swift類型創(chuàng)建之自定義一個(gè)類型詳解
這篇文章主要介紹了Swift類型創(chuàng)建之自定義一個(gè)類型詳解,本文講解了自定義原型、實(shí)現(xiàn)默認(rèn)值、支持基本布爾型初始化、支持Bool類型判斷、支持兼容各們各派的類型、完善OCBool的布爾基因體系等內(nèi)容,需要的朋友可以參考下2015-05-05
Swift實(shí)現(xiàn)多個(gè)TableView側(cè)滑與切換效果
這篇文章主要為大家詳細(xì)介紹了Swift實(shí)現(xiàn)多個(gè)TableView側(cè)滑與切換效果,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-11-11

