【问题标题】:Swift Combine: combining three signals into oneSwift Combine:将三个信号合二为一
【发布时间】:2020-04-04 21:02:49
【问题描述】:

我正在处理一个遗留库,我不能随意修改它们的代码,并且正在尝试使用 Combine 将它们编织成更易于使用的东西。我的情况是方法调用可以返回一个响应,或者一个响应和两个通知。仅响应是成功场景,响应 + 2 个通知是错误场景。我想将来自两个通知的响应和有效负载组合成一个可以传递给我的应用程序的错误。真正有趣的是,我无法保证响应或通知是否先出现,也不保证哪个通知先出现。通知来自与响应不同的线程。好消息是他们“几乎同时”进来。

为了处理通知,我愿意

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

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

【问题讨论】:

  • 听起来像是.timeout.zip 的组合。
  • 谢谢,我会直接进入那些

标签: ios swift combine


【解决方案1】:

组合三个信号的部分很简单:使用.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($0)}
            .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。所以重点是,我们得到的 first 值可以正确区分我们是否在要求的时间内收到了信号。

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

【讨论】:

  • 非常感谢。我同意,让拉链工作很好。我仍在学习超时,您的示例确实帮助我在这方面取得了进展。不过我不太明白:在 0.2 秒延迟的情况下,第二个“假”从何而来?
  • 因为下一个超时间隔到了,没有进一步的通知。当然,我们可以改变这一点,在第一个完成之后将.finished 完成发送到管道中。但这并不重要,因为一切都将在.zip 发出的第一个值中发生。
  • 如果我正在做的任何部分不清楚,请参阅我的在线书籍中的讨论:apeth.com/UnderstandingCombine/toc.html
  • 很高兴为您提供帮助。我认为您在这个遗留库之前使用 Combine 的目标非常酷。
猜你喜欢
  • 1970-01-01
  • 2014-01-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-27
  • 1970-01-01
相关资源
最近更新 更多