美文网首页
RxSwift 5 Filter Operator

RxSwift 5 Filter Operator

作者: 貘鸣 | 来源:发表于2017-10-04 22:08 被阅读56次

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

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

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

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

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

    �概述

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

    过滤型操作符

    主要有如下三种:

    • ignoreElements
    • elementAt
    • filter
    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 事件.

    而它可以用在如下情况:

    • 比如在 RxCocoa 中, 用于将观察者释放. 而无需装入 disposeBag. 但对于大多数情况而言, 放入 disposeBag 都是最佳的选择.

      比如下面的代码:

      someObservable
      .takeUntil(self.rx.deallocated)
      .subscribe(onNext: {
          print($0)
      })
      

      即当自己被释放之前, 都可以获取到源 observable 的事件, 而当 触发器 �observable(这里是 RxCocoa 中的自己) 发送自己被释放的事件时, 就不能再获取源 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")
    

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

    相关文章

      网友评论

          本文标题:RxSwift 5 Filter Operator

          本文链接:https://www.haomeiwen.com/subject/gzzcyxtx.html