【问题标题】:ReactiveCocoa - sequence of signal-producer with general error handlingReactiveCocoa - 具有一般错误处理的信号生成器序列
【发布时间】:2017-06-05 10:30:14
【问题描述】:

我有一个关于 Swift 3 的 ReactiveCocoa (v5) 的问题。在我的项目中,我有不同的服务。例如 api 或用于从磁盘保存或获取内容。这些服务正在返回 SignalProducer。我现在有一些类似调用不同服务的序列,这些服务相互依赖。这里的顺序:

  1. 调用服务获取密钥
  2. 使用key调用服务的api
  3. 从api获取数据(返回多个模型)
  4. 使用 first-model-service 保存第一个模型
  5. 使用 second-model-service 保存第二个模型

在我的序列中,我还必须将来自第二个服务调用的数据传递给模型保存。

keyService.get().flatMap(.latest) { (key) -> SignalProducer<[Data],Error> in

    return self.dataService.get()(key: key)
}
.flatMap(.latest) { (data) -> SignalProducer<Bool, Error> in

    return self.firstModelService.save(data["Model1"])
}
.flatMap(.latest) { (data) -> SignalProducer<Bool, Error> in

    //how to get data here?

    return self.secondModelService.save(data["Model2"])
}.startWithFailed({ e in

})

此外,如果序列中的SignalProducer 之一正在发送一个错误,那么整个序列将停止,并以错误作为参数调用回调。我不知道startWithFailed是不是这里的正确函数。

有没有人和我一样的情况,可以举个例子吗?我阅读了一些教程,但我无法弄清楚。

【问题讨论】:

  • 它没有按预期工作吗?乍一看,我觉得它很好,startWithFailed 也应该是正确的运算符。如果任何一个 SignalProducers 发送错误,则该错误应通过整个链传播到 startWithFailed 观察者。
  • 是的,如果您只关心处理失败案例而对成功无事可做,这对我来说是正确的。
  • 好吧,还有另一件事。你看到最后一个 flatMap 中的评论了吗?如何从那里的 api 请求中获取数据?
  • 我对这里的类型有些混淆。第一个flatMap 中的data 应该是Data 值的数组,还是应该被展平为单独的Data 值?如果您只想将data 传递给下一个flatMap,请使用mapreturn self.firstModelService.save(data["Model1"]).map { _ in data }(您必须更新您的类型注释)。

标签: swift swift3 reactive-programming reactive-cocoa reactive-swift


【解决方案1】:

您说得对,如果序列中的任何SignalProducers 失败,则以下块都不会执行,执行将直接跳到startWithFailed 中的块。

如果keyService 失败,我们不能使用dataService,如果dataService 失败,我们不能保存任何一个模型,所以这种行为对于这两个操作是有意义的。

但是,modelService 操作不相互依赖才能完成,因此应该在我们的信号模型中同时执行。要按顺序执行,您已经知道使用flatMap - 使用zipcombineLatest 并发执行同样容易(请参阅documentation)。通过与zip/combineLatest同时执行模型服务操作,我们还可以免费获得正确范围内的data

使用combineLatest,您的代码变为:

keyService.get().flatMap(.latest) { (key) -> SignalProducer<[Data],Error> in
  return self.dataService.get()(key: key)
}.flatMap(.latest) { (data) -> SignalProducer<(Bool, Bool), Error> in
  return SignalProducer.combineLatest(
    self.firstModelService.save(data["Model1"]),
    self.secondModelService.save(data["Model2"])
  )
}

你可以看到产生的信号生产者现在有Value类型的(Bool, Bool),分别表示modelService1.savemodelService2.save的结果

回复:startWithFailed

当您启动信号生成器时,您选择启动它的函数将定义回调块中的代码处理哪些事件。如果您以startWithFailed 启动SignalProducer,那么只有错误会导致您的完成块被调用。

此类操作的最佳选择通常是startWithResult,它将Result&lt;Value, Error&gt; 传递到您的完成块中,并在每个.value.failed 事件上调用您的完成块。

但是,如果您不想对成功的获取和保存采取任何操作而只需要处理错误,那么startWithFailed 确实是正确的选择。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-12-08
    • 2013-05-10
    • 1970-01-01
    • 2014-12-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多