Swift合并:将三个信号合并为一个

Swift Combine: combining three signals into one

我正在处理一个遗留库,我不能随意修改它们的代码,并且我正在尝试使用 Combine 将它们编织成更易于使用的东西。我的情况是方法调用可以 return 一个响应,或者一个响应和两个通知。 response-only 是成功场景,response + 2 notifications 是错误场景。我想将来自两个通知的响应和有效负载组合成一个错误,我可以将其传递给我的应用程序。真正有趣的是,我无法保证响应或通知是否先到,也无法保证哪个通知先到。通知来自与响应不同的线程。好消息是他们进来了 "just about the same time".

为了处理通知,我这样做

firstNotificationSink = notificationCenter.publisher(for: .firstErrorPart, object: nil)
  .sink { [weak self] notification in
    // parse and get information about the error
  }

secondNotificationSink = notificationCenter.publisher(for: .secondErrorPart, object: nil)
  .sink { [weak self] notification in
    // parse and get more information about the error
  }

要求遗留图书馆作出回应是:

func doJob() -> String {
  let resultString = libDoStuff(reference)
}

有没有办法让我使用 Combine 将这三个信号合并为一个信号,即给定 50 毫秒的时间范围?意思是,如果我得到结果和两个通知,我有一个错误响应可以传递给我的应用程序,如果我只有结果并且没有通知在 50 毫秒内到达,那么我可以将成功响应传递给我的应用程序吗?

关于组合三个信号的部分很简单:使用.zip。那不是很有趣。问题的 有趣 部分是您需要一个管道来指示通知是否在特定时间限制内到达。这是一个如何做到这一点的例子(我没有使用你的实际数字,它只是一个演示):

import UIKit
import Combine

enum Ooops : Error { case oops }

class ViewController: UIViewController {
    var storage = Set<AnyCancellable>()
    override func viewDidLoad() {
        super.viewDidLoad()
        print("start")
        NotificationCenter.default.publisher(for: Notification.Name("yoho"))
            .map {_ in true}
            .setFailureType(to: Ooops.self)
            .timeout(0.5, scheduler: DispatchQueue.main) { Ooops.oops }
            .replaceError(with: false)
            .sink {print([=10=])}
            .store(in: &self.storage)
        DispatchQueue.main.asyncAfter(deadline:.now()+0.2) {
            NotificationCenter.default.post(name: Notification.Name("yoho"), object: self)
        }
    }
}

如果 asyncAfter 延迟是 0.2,我们得到 true(后面是 false,但这并不重要;如果我们愿意,可以更改它) .如果延迟是 0.9,我们得到 false。所以关键是,我们得到的第一个值正确区分了我们是否在要求的时间内得到了信号。

好的,剩下的就很简单了:正如我之前所说,您只需将三个信号与 .zip 连接起来。它在 所有三个 发布者发出他们的 first 信号后发出一个元组——这就是你需要的所有信息,因为你已经从方法调用加上布尔值,告诉您通知是否在时限内到达。您现在可以读取该元组并对其进行分析,然后做任何您喜欢的事情。 .zip 运算符有一个 map 函数,因此您可以有序地发出分析结果。 (如果您想将 map 函数的结果转换为错误,那将需要进一步的运算符,但同样,这很容易。)