RxSwift使用技巧之过滤操作详解

 更新时间:2017年09月20日 10:18:11   作者:BigNerdCoding  
RxSwift的目的是让让数据/事件流和异步任务能够更方便的序列化处理,能够使用Swift进行响应式编程,下面这篇文章主要给大家介绍了关于RxSwift使用技巧之过滤操作的相关资料,需要的朋友可以参考下。

前言

在前面的基础之上接下来我会介绍一些常用的函数和实用技巧。首先,本文将会介绍那些用于对 next 事件进行过滤的操作。这些过滤操作类似于 Swift 标准库中的 filter 操作。它能在我们开始真正进行业务处理前先把那些不符合条件的过滤掉,而且这种函数式编程的范式也能开阔我们的思维。

Ignore 过滤

RxSwift 中最简单直接的过滤操作就是 ignoreElements 了。该操作会屏蔽所有的 next 事件,只会将注意力放在 error 和 completed 事件上。如下图所示,在整个生命周期中可观察对象的所有 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()

/* 打印结果
You're out!
*/

不过相比于残暴的全部过滤,有时候我们可能只是需要过滤某些特定的事件。例如,我们可以通过 elementAt 对特定索引号 next 进行过滤。下图演示了只响应第二个 next 事件的 elementAt 操作。

与之相应的代码为:

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()

/* 打印结果
3
*/

上面两个操作最后针对的 next 事件最多只会有一个,但是大多数时候我们其实需要筛选出一组符合条件的 next 事件。下图演示的就是使用 filter 筛选数据小于 3 的操作。

图示对应代码如下:

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()

/* 打印结果
1
2
*/

Skip 过滤

除了忽略操作外,另一个常见的过滤就是跳过操作了。在所有的跳过操作中,最简单的就属 skip 了。通过设定参数,我们就能和简单实现跳过指定个数的事件。例如,下图久演示跳过前两个事件的操作。

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()

/* 打印结果
3
4
5
*/

当然除了跳过指定索引号的事件之外,我们依旧通过 skipWhile 我们能够实现类似 filter 类似的操作。只不过 filter 会过滤整个生命周期内的符合条件的事件,而 skipWhile 在找到第一个不符合跳过操作的事件之后就不再工作。例如,下图 skipWhile 的条件是数据为奇数就跳过,但是当数据 2 执行之后 数据 3 虽然也是奇数但是不会在跳过。所以严格意义上来说 skipWhile 可能有点歧义,实际是它会跳过所有符合条件的事件,直到找到第一个能执行事件后就不再生效。

下面是跳过偶数的 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()

/* 打印结果
3
4
5
*/

到目前为止,上面的过滤操作都是基于一些静态条件。如果现在你需要根据其它可观察对象实例的行为进行过滤判断怎么办呢?所以接下来将会介绍涉及多实例的动态判断,其中最常见的就是 skipUntil 操作。该操作过程如下图,上面两行表示可观察对象的生命周期而最下面的表示观察者,直到第二行的可观察对象发送数据后第三行的观察者才能接受到第一行发送的数据。

图示对应代码:

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()

/* 打印结果
2
3
*/

Take 过滤

这是一组与 Skip 相反的过滤操作。这组操作中最基础的操作为 take ,该操作的过程完全与 skip 相反。下图演示了 take(2) 操作的过程,它只会对前两个事件进行响应而忽略后面的事件。

上图对应代码:

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()

/* 打印结果
1
2
*/

除此之外,skipWhile 也有对应的 Take 操作 takeWhile ,两者的代码结构几乎一致只不过前者是跳过操作而后者则是响应操作。不过这里我不准备介绍 takeWhile 操作(可以自己动手试下),而是介绍 takeWhile 变种 takeWhileWithIndex。其实函数名已经表明了该操作的主要功能,在 takeWhile 的基础上会加上索引 index 参数。因为有时候我们除了需要通过 value 进行过滤判断外,索引 index 也可能是一个判断维度。下图就展示了 takeWhileWithIndex 简单使用示例,对于 value 和 index 值小于 1 的事件全部跳过。

图示对应代码:

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()

/* 打印结果
3
*/

其实 Skip 组中同样存在与 takeWhileWithIndex 相对的 skipWhileWithIndex ,感兴趣可以自己检验一下。接下来我们介绍 Take 组中的最后一个操作 takeUntil 。同样地该操作是 skipUntil 的反操作,直到另一个实例对象触发后该实例对象的观察者才会停止响应。下图就是 takeUntil 操作的一个简单示例,作为观察者第三行会一直响应第一行可观察对象发送的数据,直到第二行对象触发后才停止。

对应代码:

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()

/* 打印结果
1
2
*/

Distinct 过滤

最后本文将介绍 Distinct 过滤操作 distinctUntilChanged 。对于观察者来说,有时可观察对象可能在某段时间内连续发生相同的数据。假设这些数据与 UI 相关的话,那么这里就存在不必要的刷新操作了。所以我们有必要对过滤这些连续的相同数据,减少不必要的响应操作。下图就是一个简单的示例,图中我们过滤掉了相同的后续数据,只会对第一个作出响应。

对应示例代码:

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()

/* 打印结果
1
2
3
*/

总结

本文在前面的基础上通过图示和代码介绍了主要的过滤操作。掌握好这些操作有利于我们最大化的发挥 RxSwift 功力。当然文中的代码都非常简单,所以我希望你在实际编程中不断磨练。

好了,以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流,谢谢大家对脚本之家的支持。

相关文章

  • swift指针及内存管理内存绑定实例详解

    swift指针及内存管理内存绑定实例详解

    这篇文章主要为大家介绍了swift指针及内存管理内存绑定实例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-11-11
  • Swift中的可选项Optional解包方式实现原理

    Swift中的可选项Optional解包方式实现原理

    这篇文章主要为大家介绍了Swift中的可选项Optional解包方式实现原理示例分析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-03-03
  • Swift 3中使用FMDB遇到的问题与解决方法

    Swift 3中使用FMDB遇到的问题与解决方法

    相信大家都熟悉OC使用FMDB第三方库,进行数据库操作,增、删、改、查,但最近在Swift 3中使用FMDB遇到了一些问题,下面这篇文章主要给大家介绍了关于在Swift 3中使用FMDB遇到的问题与解决方法,需要的朋友可以参考下。
    2017-07-07
  • Swift面试题及答案整理

    Swift面试题及答案整理

    虽然Swift出现的时间不久,但是它已经成为最流行的编程语言之一了。Swift的知识浩如烟海,但是怎么测试你掌握了多少?通过下面这篇整理关于Swift面试题及答案,可能会对你所掌握的Swift进行一个判断,需要的朋友可以参考借鉴。
    2017-01-01
  • Swift教程之闭包详解

    Swift教程之闭包详解

    这篇文章主要介绍了Swift教程之闭包详解,闭包可以在上下文的范围内捕获、存储任何被定义的常量和变量引用,因这些常量和变量的封闭性,而命名为“闭包(Closures)”,需要的朋友可以参考下
    2015-01-01
  • Swift中通知中心(NotificationCenter)的使用示例

    Swift中通知中心(NotificationCenter)的使用示例

    这篇文章主要给大家介绍了关于Swift中通知中心(NotificationCenter)使用的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧。
    2017-10-10
  • Swift心得笔记之运算符

    Swift心得笔记之运算符

    区别于 C 语言,在 Swift 中你可以对浮点数进行取余运算(%),Swift 还提供了 C 语言没有的表达两数之间的值的区间运算符,(a..b和a...b),这方便我们表达一个区间内的数值。
    2015-04-04
  • Swift类型创建之自定义一个类型详解

    Swift类型创建之自定义一个类型详解

    这篇文章主要介绍了Swift类型创建之自定义一个类型详解,本文讲解了自定义原型、实现默认值、支持基本布尔型初始化、支持Bool类型判断、支持兼容各们各派的类型、完善OCBool的布尔基因体系等内容,需要的朋友可以参考下
    2015-05-05
  • iOS Swift读取本地json文件报错的解决方法

    iOS Swift读取本地json文件报错的解决方法

    只要是app开发者都知道,从服务器端获得的数据要不就是json格式的数据,要么就是xml格式的数据,而这篇文章主要给大家介绍了关于iOS Swift读取本地json文件报错的解决方法,需要的朋友可以参考借鉴,下面来一起学习学习吧。
    2017-11-11
  • 深入讲解Swift的内存管理

    深入讲解Swift的内存管理

    不管在什么语言里,内存管理的内容都很重要,Swift使用自动引用计数来管理应用程序的内存使用。这表示内存管理已经是Swift的一部分,在大多数情况下,你并不需要考虑内存的管理。本文主要介绍了Swift中内存管理的相关资料,需要的朋友可以参考。
    2017-03-03

最新评论