在对RxSwift的基本概念有了一个比较全面的认识之后,在进一步开发App之前,我们要先积累更多RxSwift operators相关的知识。理解它们并不困难,你不必完全记住它们,但是至少要在心里留有印象。因为,对特定的事件序列使用正确的operator,是编写语义正确的Rx代码的重要基础。
在这一节中,我们先来看如何忽略特定的事件。从忽略全部事件到自定义指定事件,RxSwift提供了多种operators。为了演示operators的用法,我们用SPM新建了一个RxSwift项目,并在Sources目录添加了两个文件:
ignoring-ops-1其中,helper.swift中只定义了一个函数:
func example(_ description: String,
action: (Void) -> Void) {
print("================== \(description) ==================")
action()
}
它的作用有两个,一来,可以在任何测试代码执行前,打印一个提示方便我们观察结果;二来,action
可以提供一个独立的scope,方便我们利用DisposeBag
回收资源。
而我们所有的演示代码,都会编写在main.swift里。
Ignore elements
第一个要介绍的operator是ignoreElements
,它会忽略序列中所有的.next
事件。我们用一个PublishSubject<String>
来演示它的用法:
example("ignoreElements") {
let tasks = PublishSubject<String>()
let bag = DisposeBag()
tasks.subscribe { print($0) }
.addDisposableTo(bag)
tasks.onNext("T1");
tasks.onNext("T2");
tasks.onNext("T3");
tasks.onCompleted();
}
这是一个标准的PublishSubject
订阅,我们可以在控制台看到类似下面的结果:
如果我们要忽略掉所有的.next
事件,只接受.completed
事件,可以把之前的订阅代码改成这样:
tasks.ignoreElements()
.subscribe { print($0) }
.addDisposableTo(bag)
重新执行一下,就会看到下面的结果了:
ignoring-ops-1用序列图把它画出来,就是这样的:
ignoring-ops-1skip
除了一次性忽略所有的.next
之外,我们还可以选择忽略事件序列中特定个数的.next
。例如,在我们的例子里,假设队列中前两个任务都是流水线上其它人完成的,而你只需要完成第三个任务,就可以这样:
tasks.skip(2)
.subscribe {
print($0)
}
.addDisposableTo(bag)
重新执行一下,就能看到下面的结果了:
ignoring-ops-1其中,skip
表示从事件序列中的第一个元素开始,忽略其参数指定个数的事件,用序列图表示,就是这样的:
skipWhile / skipUntil
除了可以忽略指定个数的事件外,我们还可以通过一个closure自定义忽略的条件,这个operator叫做skipWhile
。但它和我们想象中有些不同的是,它不会“遍历”事件序列上的所有事件,而是当遇到第一个不满足条件的事件之后,就不再忽略任何事件了。
例如,为了忽略名称不等于T2
事件,我们编写了下面的代码:
tasks.skipWhile {
$0 != "T2"
}
.subscribe {
print($0)
}
.addDisposableTo(bag)
但执行一下,却会看到这样的结果:
ignoring-ops-1可以看到,skipWhile
只忽略了T1
,而没有忽略T3
。而这就是While
的含义,它只忽略到第一个不满足条件的事件,然后,就完成任务了。用序列图表示,就是这样的:
另外一个和skipWhile
类似的operator是skipUntil
,它不用一个closure指定忽略的条件,而是使用另外一个事件序列中的事件。例如,我们先把代码改成这样:
let tasks = PublishSubject<String>()
let bossIsAngry = PublishSubject<Void>()
let bag = DisposeBag()
tasks.skipUntil(bossIsAngry)
.subscribe {
print($0)
}
.addDisposableTo(bag)
tasks.onNext("T1");
tasks.onNext("T2");
tasks.onNext("T3");
tasks.onCompleted();
执行一下就会看到,我们不会订阅到任何事件。这就是skipUntil
的效果,它会一直忽略tasks
中的事件,直到bossIsAngry
中发生事件为止。把它用序列图表示出来,是这样的:
为了观察到这个效果,我们在T2
和T3
之间添加下面的代码:
tasks.onNext("T1");
tasks.onNext("T2");
bossIsAngry.onNext();
tasks.onNext("T3");
重新执行一下,就可以看到订阅T3
的结果了。
distinctUntilChanged
最后一个要介绍的,是通过distinctUntilChanged
忽略序列中连续重复的事件。例如下面这个例子:
example("ignoreElements") {
let tasks = PublishSubject<String>()
let bag = DisposeBag()
tasks.distinctUntilChanged()
.subscribe {
print($0)
}
.addDisposableTo(bag)
tasks.onNext("T1")
tasks.onNext("T2")
tasks.onNext("T2")
tasks.onNext("T3")
tasks.onNext("T3")
tasks.onNext("T4")
tasks.onCompleted()
}
由于T2
和T3
都属于连续重复的事件,因此它们各自的第二次出现都会被忽略,我们只能订阅到下面这样的结果:
它的序列图是这样的:
ignoring-ops-1但是,如果把T2
放到两个T3
中间,此时就没有任何连续重复的事件了,我们就会订阅到所有任务。
What's next?
以上,就是和忽略事件相关的operators,简单来说,就是从忽略全部(ignoreElements
)、到忽略指定个数(skip(n)
)、再到忽略指定条件的事件(skipWhile
和skipUntil
),最后是忽略连续重复的事件(distinctUntilChanged
)。理解了它们之后,下一节,我们来看如何获取特定的事件。
网友评论