Matching datas的核心思想是判断pipline的输出数据是否符合某个条件。
allSatisfy
如上图所示,allSatisfy
接受一个闭包作为参数,闭包的返回值为bool类型。只有当publisher输出的所有数据都让闭包返回true,pipline才会输出true。
值得注意的是,allSatisfy
是阻塞publisher的,必须等待publisher发送完.finished
事件后才会输出数据。这说明了allSatisfy计算结果的时机是在publisher发送完.finished
事件。
我们再看一个返回false的示意图:
代码如下:
cancellables = Set<AnyCancellable>()
let publisher = PassthroughSubject<String, Never>()
publisher
.allSatisfy { value in
value.count > 2
}
.sink { print($0) }
.store(in: &cancellables)
publisher.send("abc")
publisher.send("defg")
publisher.send("hijklmn")
allSatisfy
的一个扩展是tryAllSatisfy
,它允许闭包抛出异常,在这里就不解释了。
contains
由上图可看出,.contains
的用法非常简单:
- 判断publisher输出的数据是否符合条件
- 一旦发现了符合条件的数据,立刻终止pipline并返回true
- 如果publisher发送了
.finished
,未发现符合条件的数据,则返回false
值得注意的一点是,一旦contains符合了条件就会立刻终止pipline,.contains(2)
是默认写法,但它要求publisher输出的数据必须实现Equatable协议,因为只有实现了这个协议,才能判断两个值是否相等。
cancellables = Set<AnyCancellable>()
[1, 2, 3]
.publisher
.contains(2)
.sink { print($0) }
.store(in: &cancellables)
那么,在真实开发中,输出的数据可能各种各样,在不实现Equatable协议的前提下,可以使用.contains(where predicate:)
来实现,如下图所示:
可以看出,除了参数换成了闭包外,结果跟.contains(2)
完全相同,这就是声明式编程的巨大优势,我们可以自由定义闭包,这个闭包就仿佛说明书一样。
[1, 2, 3]
.publisher
.contains { value -> Bool in
value == 2
}
.sink { print($0) }
.store(in: &cancellables)
当然,用到闭包的地方一般都有try,.contains(where predicate:)
的一个扩展为.tryContains(where predicate:)
,它允许闭包中抛出异常,这里就不做解释了。