59

iOS开发进阶 - RxSwift: Filter相关方法

 5 years ago
source link: https://jesuslove.github.io/2019/03/27/iOS开发进阶-RxSwift-Filter相关方法/?amp%3Butm_medium=referral
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

万丈高楼平地起,前面两篇地基已经建好,现在开始第一层。

示例代码请移步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(_:)

从整体上了解要学习的内容,接下来详细分析各个操作作用,特点及区别联系。

Ignoring Operators

ignoreElements

特点:忽略所有的 .next 事件元素,允许终止事件通过。如: .completed.error 。是不是应该想起来什么? ignoreElements 实际上返回一个 Completable

rqiiuiu.png!web

①:表示源序列,可以被订阅

②:表示操作及参数

③:订阅

实例代码:

/// 1. ignoreElements : 忽略所有的 .next 事件元素,允许停止事件通过,如 .completed 和 .error.
/// 也许会发现:ignoreElements 实际上返回一个 Completable
example(of: "ignoreElements") {
    // 1. 创建 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

特点: 获取指定位置的元素。只要获取到指定位置的元素,订阅就终止。

iqyAneR.png!web

示例代码:

/// 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 提供了一个闭包,针对所有的元素,只要满足添加就可以输出。

EV73qq6.png!web

示例代码:

/// 3. ignoreElement 和 elementAt 过滤序列元素。有时不针对全部或单个元素操作。
/// filter 提供了一个闭包,针对所有的元素,只要满足添加就可以输出。
example(of: "filter") {
    let bag = DisposeBag()
    // 1. 创建一个序列
    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

特点: 跳过指定数量的元素。

77beiuV.png!web

示例代码:

/// 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

FBJVve7.png!web

/// 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

v22eInQ.png!web

/// 以上都是静态的条件过滤元素,如果想基于其他序列动态过滤元素怎么办?
/// 3. skipUntil : 它将保持跳过原序列所有元素,直到触发序列发射 .next 事件,开始输出后续元素。
example(of: "skipUntil") {
    let bag = DisposeBag()
    // 1. 一个源序列,一个触发序列
    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") // 触发
    subject.onNext("C")
    
    // 输出:C
}

Taking Operators

take

nIfeMbV.png!web

/// 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

iuUV3i3.png!web

/// 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

e6BZVnQ.png!web

/// 3. takeUntil: 与 skipUntil 类似
/// 持续获取源序列中元素,直到触发序列发送 .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") // 触发序列终止源序列
    subject.onNext("C")
    // 输出:A B
    // 思考:是不是可以通过 takeUntil 监控 VC 的销毁。
}

Distinct Operators

distinctUntilChanged

mqYvMji.png!web

/// 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)
}

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK