iOS開發(fā)進階 - RxSwift :Filter相關操作

前言

萬丈高樓平地起,前面兩篇地基已經建好,現(xiàn)在開始第一層。
示例代碼請移步Github
RxSwift 4.4

從本篇開始接下來幾篇文章會詳細學習 RxSwiftOperators,作為 Rx編程的基石,可以使用它來轉換,處理和響應事件。

Operators 分為四個部分:

  • Filtering Operators:過濾
  • Transforming Operators : 轉換
  • Combing Operators : 組合
  • Time-Based Operators : 基于時間操作

接下來學習過濾相關的操作。

Filtering Operators

過濾操作分為四類:

分類 主要方法 說明
Ignoring Operators ignoreElements elementAt filter 用于忽略一些元素
Skipping Operators skip skipWhile skipUntil
Taking Operators take takeWhile takeUntil
Distinct Operators distinctUntilChange distinctUntilChanged(_:)

從整體上了解要學習的內容,接下來詳細分析各個操作作用,特點及區(qū)別聯(lián)系。

Ignoring Operators

ignoreElements

特點:忽略所有的 .next 事件元素,允許終止事件通過。如:.completed.error。是不是應該想起來什么?ignoreElements 實際上返回一個 Completable。

raywenderlich.com

①:表示源序列,可以被訂閱
②:表示操作及參數
③:訂閱

實例代碼:

/// 1. ignoreElements : 忽略所有的 .next 事件元素,允許停止事件通過,如 .completed 和 .error.
/// 也許會發(fā)現(xiàn):ignoreElements 實際上返回一個 Completable
example(of: "ignoreElements") {
    // 1. 創(chuàng)建 subject
    let strikes = PublishSubject<String>()
    let disposeBag = DisposeBag()
    // 2. 添加訂閱
    strikes
        .ignoreElements() // 忽略所有元素
        .subscribe{_ in
            print("You are out!")
        }
        .disposed(by: disposeBag)
    
    strikes.onNext("X") // 無輸出
    strikes.onNext("Y") // 無輸出
    
    strikes.onCompleted() // 輸出 You are out!
}

elementAt

特點: 獲取指定位置的元素。只要獲取到指定位置的元素,訂閱就終止。

raywenderlich.com

示例代碼:

/// 2. elementAt : 獲取指定位置的元素。
/// 只要獲取到指定位置的元素,訂閱就終止。
example(of: "elementAt") {
    let strikes = PublishSubject<String>()
    let bag = DisposeBag()
    
    strikes
        .elementAt(2) // 獲取序列中 index = 2 的元素
        .subscribe(onNext: { element in
            print("\(element) - You are out!")
        })
        .disposed(by: bag)
    strikes.onNext("X") // 無輸出
    strikes.onNext("Y") // 無輸出
    strikes.onNext("Z") // index = 2 輸出
    
    // 輸出:Z - You are out!
}

filter

特點:ignoreElementelementAt 過濾序列元素。有時不針對全部或單個元素操作。filter 提供了一個閉包,針對所有的元素,只要滿足添加就可以輸出。

raywenderlich.com

示例代碼:

/// 3. ignoreElement 和 elementAt 過濾序列元素。有時不針對全部或單個元素操作。
/// filter 提供了一個閉包,針對所有的元素,只要滿足添加就可以輸出。
example(of: "filter") {
    let bag = DisposeBag()
    // 1. 創(chuàng)建一個序列
    Observable.of(1, 2, 3, 4, 5, 6)
        .filter{ $0 % 2 == 0} // 2. 過濾偶數
        .subscribe(onNext: { // 3. 訂閱
            print($0)
        })
        .disposed(by: bag)
    // 輸出: 2 4 6
}

Transforming Operators

skip

特點: 跳過指定數量的元素。

示例代碼:

/// 1. skip() : 跳過指定數量的元素

example(of: "skip") {
    let bag = DisposeBag()
    
    // 1. 序列
    Observable.of("A", "B", "C", "D", "E", "F")
        .skip(3) // 2. 跳過三個元素
        .subscribe( onNext: { // 3. 訂閱
            print($0)
        })
        .disposed(by: bag)
    // 輸出: D E F
}

skipWhile

/// 2. skipWhile : 像 skip 一樣決定哪些元素被忽略。
/// skipWhile 只跳過元素,直到第一個元素被允許通過,然后所有剩余的元素都被允許通過。
/// 閉包 返回 true 對應的元素將被忽略;返回 false 對應的元素通過。
/// 與 filter 操作相反。
example(of: "skipWhile") {
    let bag = DisposeBag()
    
    Observable.of(2, 2, 3, 4, 4) // 1. 序列
        .skipWhile { $0 % 2 == 0} // 2. 跳過 開始時的 偶數
        .subscribe(onNext: {
            print($0)
        })
        .disposed(by: bag)
    // 輸出: 3 4 4
}

skipUntil

/// 以上都是靜態(tài)的條件過濾元素,如果想基于其他序列動態(tài)過濾元素怎么辦?
/// 3. skipUntil : 它將保持跳過原序列所有元素,直到觸發(fā)序列發(fā)射 .next 事件,開始輸出后續(xù)元素。
example(of: "skipUntil") {
    let bag = DisposeBag()
    // 1. 一個源序列,一個觸發(fā)序列
    let subject = PublishSubject<String>()
    let trigger = PublishSubject<String>()
    
    // 2.
    subject
        .skipUntil(trigger) // 直到 trigger 序列有 .next 事件
        .subscribe(onNext: {
            print($0)
        })
        .disposed(by: bag)
    
    subject.onNext("A")
    subject.onNext("B") // 未輸出
    trigger.onNext("X") // 觸發(fā)
    subject.onNext("C")
    
    // 輸出:C
}

Taking Operators

take

/// Taking 是與 Skipping 相反的操作。
/// 1. take: 獲取幾個元素
example(of: "take") {
    let bag  = DisposeBag()
    
    Observable.of(4, 5, 6, 7, 8, 9)
        .take(3) // 獲取三個元素
        .subscribe(onNext: {
            print($0)
        })
        .disposed(by: bag)
    // 輸出: 4 5 6
}

takeWhile

/// 2. takeWhile: 與 skipWhile 類似,不同點是用 taking 代替 skipping
example(of: "takeWhile") {
    let bag = DisposeBag()
    
    Observable.of(2, 2, 4, 4, 6, 6)
        .enumerated() // 1. 獲取元組包含 index 和 element
        .takeWhile({ index, integer in // 2. 直到條件不成立停止
            integer % 2 == 0 && index < 3
        })
        .map { $0.element } // 3. 獲取元素,生成只包含元素的序列
        .subscribe(onNext: { // 4. 訂閱輸出
            print($0)
        })
        .disposed(by: bag)
    
    // 輸出: 2 2 4
}

takeUntil

/// 3. takeUntil: 與 skipUntil 類似
/// 持續(xù)獲取源序列中元素,直到觸發(fā)序列發(fā)送 .next 事件。
example(of: "takeUntil") {
    let bag = DisposeBag()
    // 1.
    let subject = PublishSubject<String>()
    let trigger = PublishSubject<String>()
    
    // 2.
    subject
        .takeUntil(trigger)
        .subscribe(onNext: {
            print($0)
        })
        .disposed(by: bag)
    // 3.
    subject.onNext("A")
    subject.onNext("B")
    trigger.onNext("1") // 觸發(fā)序列終止源序列
    subject.onNext("C")
    // 輸出:A B
    // 思考:是不是可以通過 takeUntil 監(jiān)控 VC 的銷毀。
}

Distinct Operators

distinctUntilChanged

/// 1. distinctUntilChanged : 阻止下一個重復元素
/// 只阻止相鄰重復元素。
example(of: "distinctUntilChanged") {
    let bag = DisposeBag()
    
    Observable.of("A", "A", "B", "B", "A")
        .distinctUntilChanged()
        .subscribe(onNext: {
            print($0)
        })
        .disposed(by: bag)
    // 輸出:A B A
}

distinctUntilChanged(_:)

/// 2. distinctUntilChanged(_:) 自定義比較
example(of: "distinctUntilChanged(_:)") {
    let bag = DisposeBag()
    // 1
    let formatter = NumberFormatter()
    formatter.numberStyle = .spellOut // 朗讀形式,英文,例如:110 ==> ["one", "hundred", "ten"]
    // 2. 序列
    Observable<NSNumber>.of(10, 110, 20, 200, 210, 310)
        // 3
        .distinctUntilChanged { a, b in
            guard let aWords = formatter.string(from: a)?.components(separatedBy: " "),
            let bWords = formatter.string(from: b)?.components(separatedBy: " ")
            else {return false}
            print(aWords, bWords)
            var containsMatch = false
            for aWord in aWords where bWords.contains(aWord) {
                containsMatch = true
                break
            }
            return containsMatch
            /*
             第一次:["ten"] ["one", "hundred", "ten"] ==> true, 跳過 110
             第二次:["ten"] ["twenty"] ==> false
             第三次:["twenty"] ["two", "hundred"] ==> false
             第四次:["two", "hundred"] ["two", "hundred", "ten"] ==> true,跳過 210
             第五次:["two", "hundred"] ["three", "hundred", "ten"] ==> true, 跳過 310
             */
            
        }
        // 訂閱
        .subscribe(onNext: {
            print($0)
        })
        .disposed(by: bag)
}
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容