如何在 Combine 中对两个具有不同故障类型的发布者进行 flatMap

How to flatMap two Publishers with different Failure types in Combine

我在我的 Rx 代码中遵循一个模式,我通常有一个 Observable 触发器,我 flatMap 为网络请求创建另一个 Observable。一个简化的例子:

enum ViewModelError: Error {
  case bang
}

enum DataTaskError: Error {
  case bang
}

func viewModel(trigger: Observable<Void>,
               dataTask: Observable<Result<SomeType, DataTaskError>>) -> Observable<Result<AnotherType, ViewModelError>> {
  let apiResponse = trigger
    .flatMap { dataTask }
}

我在使用 Combine 等效项时遇到了一些问题。我可以使用 Result 作为输出类型并使用 Never 作为 Failure 类型,但这感觉像是对 API.

的误用
func viewModel(trigger: AnyPublisher<Void, Never>,
               dataTask: AnyPublisher<SomeType, DataTaskError>) -> AnyPublisher<AnotherType, ViewModelError> {
  let apiResponse = trigger
    .flatMap { dataTask }
}

我遇到编译错误:

Instance method 'flatMap(maxPublishers:_:)' requires the types 'Never' and 'DataTaskError' be equivalent

我可以使用 mapError 并将两个错误都转换为 Error,但我需要一个 DataTaskError 才能创建我的 ViewModelError。

这感觉应该不难,而且似乎是一个相当常见的用例。我可能只是误解了一些基本原理,将不胜感激指出正确方向。

当您有一个失败类型为 Never 的发布者时,您可以使用 setFailureType(to:) 来匹配另一个发布者的失败类型。请注意,根据文档,此方法只能在故障类型为 Never 时使用。当你有一个实际的故障类型时,你可以用 mapError(_:) 转换错误。所以你可以这样做:

func viewModel(trigger: AnyPublisher<Void, Never>,
               dataTask: AnyPublisher<SomeType, DataTaskError>) -> AnyPublisher<AnotherType, ViewModelError> {
  trigger
    .setFailureType(to: ViewModelError.self) // Publisher<Void, ViewModelError>
    .flatMap {
        dataTask // Publisher<SomeType, DataTaskError>
            .mapError { _ in ViewModelError.bang } // Publisher<SomeType, ViewModelError>
            .map { _ in AnotherType() } // Publisher<AnotherType, ViewModelError>
    }
.eraseToAnyPublisher()
}