在Combine 中处理错误的最佳方法是什么?

oma*_*yao 5 swift swiftui combine

我正在尝试使用以下代码将下载的 JSON 解码为结构。

static func request(url: URL) -> AnyPublisher<SomeDecodableStruct, Error> {
    return URLSession.shared.dataTaskPublisher(for: url)
        .map { $0.data }
        .decode(type: SomeDecodableStruct.self, decoder: JSONDecoder())
        .eraseToAnyPublisher()
}
Run Code Online (Sandbox Code Playgroud)

但是,如果处理失败,我希望您返回有关请求处理失败或解码处理失败的信息。因此,我将FailureReason符合Error协议的enum定义如下。

enum FailureReason : Error {
    case sessionFailed(error: URLError)
    case decodingFailed
}

static func request(url: URL) -> AnyPublisher<SomeDecodableStruct, FailureReason> {
    // ???
}
Run Code Online (Sandbox Code Playgroud)

我如何定义request(url:)满足这一点的FailureReason

Jos*_*ann 6

对于错误,Combine 是强类型的,因此您必须使用mapError或像 RxSwift 一样草率将错误转换为正确的类型并将所有内容衰减为Error.

enum NetworkService {
  enum FailureReason : Error {
      case sessionFailed(error: URLError)
      case decodingFailed
      case other(Error)
  }

  static func request<SomeDecodable: Decodable>(url: URL) -> AnyPublisher<SomeDecodable, FailureReason> {
    return URLSession.shared.dataTaskPublisher(for: url)
      .map(\.data)
      .decode(type: SomeDecodable.self, decoder: JSONDecoder())
      .mapError({ error in
        switch error {
        case is Swift.DecodingError:
          return .decodingFailed
        case let urlError as URLError:
          return .sessionFailed(error: urlError)
        default:
          return .other(error)
        }
      })
      .eraseToAnyPublisher()
  }
}
Run Code Online (Sandbox Code Playgroud)

  • 很好的解决方案!只是一个问题,我看到第一件事是映射数据 ```.map(\.data)```,因此 ```dataTaskPublisher``` 输出的响应被忽略,那么如果某些 API 返回错误像 HTTP 404 一样,我们如何捕获它? (3认同)