首页 > 解决方案 > 创建一个未完成发布者的捕获/替换错误对应项?

问题描述

我正在努力处理 Combine 中的错误,发现捕获替换错误完成并结束发布者非常违反直觉。例如,即使我处理了异常,这也会结束发布者:

Just([1, 2, 3, NaN, 5, 6])
   .tryMap { _ in throw DummyError() }
   .catch { _ in Just(4) } // or .replaceError(with: 4)
   .sink { print($0) } // <-- ends at 4 and ignores 5, 6, and anything ever again

如果发布者订阅了某些系统更改,第一个错误将使我的应用程序死机,直到用户重新启动应用程序。我想创建一个catch不会结束发布者的对应项。我知道flatMap它被用于此,但这会产生另一个复杂的维度,例如反转内部/外部发布者、发布者无限复制、背压等。

有没有办法做这样的事情:

Just([1, 2, 3, NaN, 5, 6])
   .tryMap { _ in throw DummyError() }
   .ignoreError { error in
        log("Error occurred: \(error)")
   }
   .sink { print($0) } // 1, 2, 3, 5, 6

如何将此意图封装在一个简单的自定义链命令中ignoreError,并让我的发布者继续存在?

标签: swiftcombine

解决方案


完成管道的错误是发布者和订阅者工作合同的一部分。这是有道理的。如果上游发布者抛出错误并且不知道如何自行恢复,则基本完成。这与抛出错误的函数没有什么不同。

在您的示例中,tryMap抛出一个错误,虽然下游喜欢replaceError可以转换其下游的错误,但它不期望来自其上游的更多值,所以它也完成了。

flatMap将管道的其余部分与抛出错误的发布者隔离开来。换句话说,上游flatMap不会抛出错误,并且flatMap自身也不会抛出错误,因为返回的内部发布者(带有Just//的管道tryMapcatch会处理错误。

Just([1, 2, 3, 5, 6])
   .flatMap {
      Just($0)
        .tryMap { _ in throw DummyError() }
        .catch { _ in Just(4) } 
   }
   .sink { print($0) } 

推荐阅读