【问题标题】:How to execute producerB if and only if producerA doesn't throw an error?当且仅当 producerA 不抛出错误时,如何执行 producerB?
【发布时间】:2017-10-05 00:54:43
【问题描述】:

我正在尝试使用以下场景 我有两个制作人 A 和 B。 producerB 应该仅在 producerA 成功执行时执行,并且如果 producerA 抛出错误,则处理错误并停在那里。所以我尝试了类似的方法。

producerA.flatMapError {
    // handle error and stop right here 
}.then(producerB).startWithResult { 
    // ...
}

看起来producerB 会执行,即使producerA 抛出错误。 请帮助我如何使它适用于我的场景。

【问题讨论】:

  • Map / flatMap 返回一个数组。如果它返回错误是什么意思?

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


【解决方案1】:

问题是,“不引发错误”的确切含义是什么。

Signal/SignalProducer 上的事件序列有一个 precisely defined semantic

有任意数量的 Value(从 0 - x)事件,最后是 completedfailedinterrupted 事件。之后就没有更多的事件了。

通常您可以说大多数运算符仅对value 事件进行操作,并立即传播failed 事件(不对其进行操作)。如果您不确定特定的运算符,请查看该运算符的文档,该文档非常清楚失败事件的行为。


所以理解问题的一种方法是说producerA 成功完成时(在任意数量的value 事件之后),然后启动producerB 并且如果producerA 发送failed 事件,那就不要了。

在这种情况下,then 运算符正是您所需要的。它将在 producerA 完成后立即启动 producerB,但如果 producerA 失败,不会

producerA.then(producerB)
  .start(Signal.Observer(value: { value in
    print("Value \(value)")
  }, failed: {error in
    print("Error \(error)")
  }))

请注意,您不要希望在此处使用 flatMapError,因为这会(取决于您在块中的错误处理方式)将 failed 事件转换为 value 事件,这将最终触发producerB


另一种理解问题的方法是说producerA 上的每个非错误事件都应该触发一次producerB

在这种情况下,您可以在 producerA 的事件上使用 flatMap 来为 producerA 上的每个事件返回一个 producerB。再次注意,flatMap 会立即传播failed 事件,因此producerA 上的failed 事件将导致整个链失败没有执行producerB

producerA.flatMap(.concat) { _ in return producerB }
  .start(Signal.Observer(value: { value in
    print("Value \(value)")
  }, failed: {error in
    print("Error \(error)")
  }))

【讨论】:

  • 好答案。我发现一个很好的思考方式是flatMapError 基本上是用来捕获错误的。其实就是used to be called catch。因此,如果您确实希望错误终止信号链,则不应使用它。我要补充一点,如果您不希望整个链因错误而终止,那么您可以将flatMapError after then.(producerB).
  • @MeXx 我在第一种方法中看到了一些问题。假设第一个生产者没有产生错误,而第二个生产者产生了错误,它正在打印值并且它永远不会进入失败的块。
  • @coolly,producerA 发送它的值后,它完成了吗? producerB 只会在 producerA 完成后开始。如果您希望producerBproducerA 发送值时启动,您应该使用flatMap 的第二种方法。
【解决方案2】:

试试这个:

func scenario() -> SignalProducer<MyValueType, MyErrorType> {
        return SignalProducer { observer, _ in
            producerA.startWithResult({ (res) in
                switch res {
                case .success(let value):
                    observer.send(value: value)
                    observer.sendCompleted()
                case .failure(let error):
                    print(error)//handle your error here
                    observer.send(error: err)
                }
            })

        }.then(producerB)
    }

scenario().start()

您创建一个自定义 SignalProducer 并通过告诉观察者根据您的场景进行操作来定义所需的行为。

【讨论】:

    猜你喜欢
    • 2020-01-27
    • 2020-04-08
    • 1970-01-01
    • 1970-01-01
    • 2023-03-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-30
    相关资源
    最近更新 更多