处理 Combine 错误的最佳方法是什么?
What is the best way to handle errors in Combine?
我正在尝试将下载的 JSON 解码为具有以下代码的结构。
static func request(url: URL) -> AnyPublisher<SomeDecodableStruct, Error> {
return URLSession.shared.dataTaskPublisher(for: url)
.map { [=10=].data }
.decode(type: SomeDecodableStruct.self, decoder: JSONDecoder())
.eraseToAnyPublisher()
}
但是,如果处理失败,我想请您return提供有关请求处理失败或解码处理失败的信息。
因此,我定义了符合Error
协议的FailureReason
枚举如下。
enum FailureReason : Error {
case sessionFailed(error: URLError)
case decodingFailed
}
static func request(url: URL) -> AnyPublisher<SomeDecodableStruct, FailureReason> {
// ???
}
如何定义满足此 FailureReason
的 request(url:)
?
在这种情况下,我不会将发布者声明为 Failure
类型而非 Never
。否则,Publisher 将发送一个包含它遇到的第一个错误的完成并完全停止发布。制作 Result
类型的 Output
会好得多。在每个可能产生错误的步骤之后,您使用 .mapError
将其映射到您的错误类型,最后捕获错误和 return Result.failure
func request(url: URL) -> AnyPublisher<Result<SomeDecodableStruct, FailureReason>, Never> {
return URLSession.shared.dataTaskPublisher(for: url)
.mapError { Error.sessionFailed(error: [=10=]) }
.map { [=10=].data }
.decode(type: SomeDecodableStruct.self, decoder: JSONDecoder())
.map { Result<SomeDecodableStruct, FailureReason>.success([=10=])}
.mapError { _ in Error.decodingFailed }
.catch { Just<Result<SomeDecodableStruct, FailureReason>>(.failure([=10=])) }
.eraseToAnyPublisher()
}
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()
}
}
我正在尝试将下载的 JSON 解码为具有以下代码的结构。
static func request(url: URL) -> AnyPublisher<SomeDecodableStruct, Error> {
return URLSession.shared.dataTaskPublisher(for: url)
.map { [=10=].data }
.decode(type: SomeDecodableStruct.self, decoder: JSONDecoder())
.eraseToAnyPublisher()
}
但是,如果处理失败,我想请您return提供有关请求处理失败或解码处理失败的信息。
因此,我定义了符合Error
协议的FailureReason
枚举如下。
enum FailureReason : Error {
case sessionFailed(error: URLError)
case decodingFailed
}
static func request(url: URL) -> AnyPublisher<SomeDecodableStruct, FailureReason> {
// ???
}
如何定义满足此 FailureReason
的 request(url:)
?
在这种情况下,我不会将发布者声明为 Failure
类型而非 Never
。否则,Publisher 将发送一个包含它遇到的第一个错误的完成并完全停止发布。制作 Result
类型的 Output
会好得多。在每个可能产生错误的步骤之后,您使用 .mapError
将其映射到您的错误类型,最后捕获错误和 return Result.failure
func request(url: URL) -> AnyPublisher<Result<SomeDecodableStruct, FailureReason>, Never> {
return URLSession.shared.dataTaskPublisher(for: url)
.mapError { Error.sessionFailed(error: [=10=]) }
.map { [=10=].data }
.decode(type: SomeDecodableStruct.self, decoder: JSONDecoder())
.map { Result<SomeDecodableStruct, FailureReason>.success([=10=])}
.mapError { _ in Error.decodingFailed }
.catch { Just<Result<SomeDecodableStruct, FailureReason>>(.failure([=10=])) }
.eraseToAnyPublisher()
}
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()
}
}