RxSwift 5 Filter Operator

2017-10-04  本文已影响56人  貘鸣

operator 也是 Rx 的基本元素, 通过它, 可以对 observable 中的事件序列进行操作.� 比如�可以去简单地进行加减. 通过 �operator 的链式表达, 可以实现许多复杂的�逻辑.

本部分首先学习 filter 类型的操作符, 然后是 transform 类型的操作符, 然后再看 combining 类型的操作符. 最后是一些基于时间的操作符, 比如延迟事件, 组合一段时间内的事件等等.

学习完本部分, 就具备了编写一些简单的 RxSwift app 的能力.

学习一个新的技术栈和�建造一栋摩天大楼是一个道理, 首先要打好打牢基础. 在之前的学习中已经学会了Observable, subject, RxSwift 中的内存管理等基础性内容. 下面就在这些的基础上, 再向上学习.

本章中会讲如何通过 RxSwift 的 过滤操作符来操作 next 事件, 这样最终观察者接收到的就是它自己想要接收的数据.

�概述

这里直入主题, 我们先来看再 RxSwift 中如何使用过滤操作符.

过滤型操作符

主要有如下三种:

ignoreElements 操作符

这个操作符的作用是过滤掉所有的 next 事件:

let disbag = DisposeBag()
let sbj = PublishSubject<Int>()
sbj
    // .ignoreElements()
    .subscribe(onNext: {
        print($0)
    }, onError: {
        print($0)
    }, onCompleted: {
        print("complete")
    }, onDisposed: {
        print("dispose")
    })
    .addDisposableTo(disbag)
sbj.onNext(1)
sbj.onNext(2)
sbj.onCompleted()

若不加 ignoreElements, 则输出为:

1
2
complete
dispose

而加了的话:

complete
dispose

可以看到, ignoreElement 操作符的作用的确是将所有的 next 事件过滤掉.

elementAt 操作符

比如只想接收序列中的某个下标位置的元素(从0开始计数), 可以使用 elementAt 操作符.

elementAt 操作符的参数越界的话并不会崩溃, 只会打印错误信息.

上面这两个操作符都是属于过滤操作符中的"忽略"子类中的操作符.

若需要特殊的过滤条件, 则可以使用 filter 操作符.

filter 的原理是利用一个过滤条件块来, 在里面将过滤条件应用到所有的元素上, 这样即可对元素进行过滤. 只有当条件为真的元素才不会被过滤. 即需要保留的元素在应用条件时候的判断结果为真.

exampleOf("过滤", operation: {
    let disposebag = DisposeBag()
    let obsv = Observable.of(1, 2, 3, 4, 56)
    obsv
        .filter({ elem in
            elem > 3
        })
        .subscribe(onNext: {
        print($0)
    }).addDisposableTo(disposebag)
})

上述首先对 observable 的事件序列应用了过滤操作符, 过滤掉所有小于 3 的元素. 输出为:

过滤
4
5
6

跳读操作符(skip)

如果想要自动跳过若干个元素时, 就可以使用 skip 操作符.

比如有三天的天气预报可以被观察, 但只想要今天的, 就可以跳过前两天的预报:

exampleOf("skip", operation: {
    let obsv = Observable.from([1, 2, 3, 48])
    obsv.skip(3).subscribe(onNext: {
        print($0)
    }).addDisposableTo(disBag)
})

输出为:

skip
4
8

实际上 skip 是一个操作符家族, 里面有诸如 skipWhile, 它允许在 skip 的时候同时指定条件. 和 filter 不同的是, skipWhile 是遇到第一个不能 skip 的元素之后, 就不再进行判断了, 后面所有的元素都放行.

并且, skipWhile 的判断条件中, 如果满足条件的会被跳过. 结合起来即: 遇到第一个不满足判断条件的(返回值为 false 的)�元素及其后面的所有元素都会被观察者接收到.

比如下面的代码:

exampleOf("skipWhile", operation: {
    let obsv = Observable.from([1, 2, 3, 48, 1, 2, 3])
    obsv.skipWhile({ elem in
        elem * 2 < 8
    }).subscribe(onNext: {
        print($0)
    }).addDisposableTo(disBag)
})

则其输出为:

skipWhile
4
8
1
2
3

到目前为止, 所有的过滤都是使用一些静态条件. 但如果需要基于其他的 observable 来动态过滤元素呢?

下面就来介绍一些这样的 operator. 首先来看的是 skipUntil, 它会持续在� "源 observable" (就是观察者观察的那个 observable) 中跳过元素, 直到� "触发器 observable"(即另外一个 observable) 发送了 next 事件(而 complete 和 error 均无作用), 此时源 observable 中的后续的所有事件就不会再被跳过了.

比如如下代码:

exampleOf("skipUntil", operation: {
    let sourceObsv = PublishSubject<Strin()
    let triggerObsv = PublishSubject<Strin()
    sourceObsv
    .skipUntil(trigger)
    .subscribe(onNext: {
        print($0)
    }).addDisposableTo(disBag)
    sourceObsv.onNext("A")
    sourceObsv.onNext("B")
    triggerObsv.onNext("something")
    sourceObsv.onNext("C")
})
skipUntil
C

Taking 操作符

Taking 的效果正好和 skip 相反.

比如如下代码:

exampleOf("taking", operation: {
    let obsv = Observable.from([1, 2, 3, 48, 1, 2, 3])
    obsv
        .take(3)
        .subscribe(onNext: {
        print($0)
    }).addDisposableTo(disBag)
})

则输出结果是:

taking
1
2
3

take(_ count:) 操作符的作用是只获取事件序列中的 count 个元素.

相应的, 也有 takeWhile 操作符, 它和 skipWhile 的区别是它一直去取满足条件的, 直到遇到第一个不满足条件的, 而 skipWhile 是满足条件的都被跳过, 直到遇到第一个不满足条件的.

另外还有些情况下需要� takeWhile 满足条件的同时满足�指定的元素下标要求, 此时就可以使用 takeWhileWithIndex:

exampleOf("takeWhileWithIndex", operation: {
    let obsv = Observable.from([5, 4, 8, 12, 3])
    obsv
        .takeWhileWithIndex({ value, idx in
            return value > 3 && idx < 5
        })
        .subscribe(onNext: {
            print($0)
        })
        .addDisposableTo(disBag)
})

输出为:

takeWhileWithIndex
5
4
8

即它去取满足条件的元素, 直到遇到第一个不满足条件的, 而后面的�都不通过.

另外还有 �skipWhileWithIndex, 不同点是它是去跳过. 而和 skipUntil 类似, 有 takeUntil 操作符, 它的作用是一直�允许取 "源 observable" 中的元素, 直到 "触发器 observable" 发送 next 事件.

而它可以用在如下情况:

Distinct 操作符

下面来看一些可以防止多次重复元素通过的操作符.

先来看 distinctUntilChanged 操作符:

1---2---2---1

distinctUntilChanged

1---2------1

它的作用就是过滤掉序列中一次或多次相邻元素是相同的情况.

比如如下代码:

example(of: "Distinct Operator") {
    Observable.of("A", "B", "A", "A", "B", "B")
        .distinctUntilChanged()
        .subscribe(onNext: {
            print($0)
        })
        .addDisposableTo(disposeBag)
}

输出为:

--- Example of: Distinct Operator ---
A
B
A
B

而操作符的判断依据是根据 Equatable 协议, 由于 String 是实现了该协议的, 故可以对 String 类型的序列使用.

但如果是没有实现该协议的元素类型, 要想判断的话, 可以先去实现该协议. 或者是可以使用 distinctUntilChanged(_:) 提供判断条件即可.

example(of: "Distinct with condition") {
    let elem0 = MyElemType(value: 1, name: "elem0")
    let elem1 = MyElemType(value: 2, name: "elem1")
    let elem2 = MyElemType(value: 2, name: "elem2")
    let elem3 = MyElemType(value: 1, name: "elem3")
    Observable.of(elem0, elem1, elem2, elem3)
        .distinctUntilChanged({ (elemA, elemB) -Bool in
            elemA.value == elemB.value
        })
        .subscribe(onNext: {
            print($0)
        })
        .addDisposableTo(disposeBag)
}

输出为:

--- Example of: Distinct with condition ---
MyElemType(value: 1, name: "elem0")
MyElemType(value: 2, name: "elem1")
MyElemType(value: 1, name: "elem3")

可以看到, 通过条件来判断两个元素是否相等操作起来十分方便.

上一篇下一篇

猜你喜欢

热点阅读