Combine之Operator(Matching datas 数据匹配)

802 阅读1分钟

github.com/agelessman/…

Matching datas的核心思想是判断pipline的输出数据是否符合某个条件。

allSatisfy

image.png

如上图所示,allSatisfy接受一个闭包作为参数,闭包的返回值为bool类型。只有当publisher输出的所有数据都让闭包返回true,pipline才会输出true。

值得注意的是,allSatisfy是阻塞publisher的,必须等待publisher发送完.finished事件后才会输出数据。这说明了allSatisfy计算结果的时机是在publisher发送完.finished事件。

我们再看一个返回false的示意图:

image.png

代码如下:

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

image.png

由上图可看出,.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:)来实现,如下图所示:

image.png

可以看出,除了参数换成了闭包外,结果跟.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:),它允许闭包中抛出异常,这里就不做解释了。