本篇文章介绍的是Combine开发过程中对错误的捕捉和处理行为,其也可以归类到常见运算符之中
catch
catch
用于捕获错误并提供一个替代的发布者。
import Combine
enum MyError: Error {
case somethingWentWrong
}
let failPublisher = Fail<String, MyError>(error: MyError.somethingWentWrong)
let catchPublisher = failPublisher
.catch { _ in
return Just("Recovered from error")
}
let cancellable = catchPublisher
.sink(receiveCompletion: { completion in
switch completion {
case .finished:
print("Completed")
case .failure(let error):
print("Error: (error)")
}
}, receiveValue: { value in
print("Received value: (value)")
})
// 输出:
// Received value: Recovered from error
// Completed
retry
retry
会在发布者失败时,重新尝试订阅。
import Combine
var attemptCount = 0
let retryPublisher = Deferred {
return Future<String, MyError> { promise in
attemptCount += 1
if attemptCount < 3 {
promise(.failure(MyError.somethingWentWrong))
} else {
promise(.success("Success after (attemptCount) attempts"))
}
}
}
.retry(3)
let cancellable = retryPublisher
.sink(receiveCompletion: { completion in
switch completion {
case .finished:
print("Completed")
case .failure(let error):
print("Error: (error)")
}
}, receiveValue: { value in
print("Received value: (value)")
})
// 输出:
// Received value: Success after 3 attempts
// Completed
tryMap
tryMap
类似于 map
,但允许抛出错误。
import Combine
let numbers = [1, 2, 3, 4, 5]
let publisher = numbers.publisher
enum MyError: Error {
case invalidNumber
}
let tryMapPublisher = publisher
.tryMap { number -> Int in
if number == 3 {
throw MyError.invalidNumber
}
return number * 2
}
let cancellable = tryMapPublisher
.sink(receiveCompletion: { completion in
switch completion {
case .finished:
print("Completed")
case .failure(let error):
print("Error: (error)")
}
}, receiveValue: { value in
print("Received value: (value)")
})
// 输出:
// Received value: 2
// Received value: 4
// Error: invalidNumber
mapError
mapError
用于将错误转换为另一种错误类型。
import Combine
enum OriginalError: Error {
case somethingWentWrong
}
enum MappedError: Error {
case mappedError
}
let failPublisher = Fail<String, OriginalError>(error: OriginalError.somethingWentWrong)
let mapErrorPublisher = failPublisher
.mapError { _ in
return MappedError.mappedError
}
let cancellable = mapErrorPublisher
.sink(receiveCompletion: { completion in
switch completion {
case .finished:
print("Completed")
case .failure(let error):
print("Error: (error)")
}
}, receiveValue: { value in
print("Received value: (value)")
})
// 输出:
// Error: mappedError
replaceError
replaceError
是一种用于处理错误的操作符。它允许我们在遇到错误时,替换为一个默认值以确保数据流继续正常流动。它的作用是将错误替换为指定的输出值 output
。
假设我们有一个简单的网络请求示例,通过 URLSession
发起请求,并处理可能的错误情况。
import Combine
import Foundation
private var cancellables: [AnyCancellable] = []
enum DataError: Error {
case invalidURL
case networkError
case parsingError
}
// 通过 URLSession.shared.dataTaskPublisher 发起一个网络请求,并尝试将接收到的数据转换为字符串。
func fetchDataFromURL(url: URL) -> AnyPublisher<String, DataError> {
URLSession.shared.dataTaskPublisher(for: url)
// 捕获可能的错误(例如网络错误或解析错误),并将其映射为 DataError 类型。
.tryMap { data, _ in
guard let string = String(data: data, encoding: .utf8) else {
throw DataError.parsingError
}
return string
}
.mapError { error in
if let urlError = error as? URLError {
return .networkError
} else {
return .parsingError
}
}
.eraseToAnyPublisher()
}
// 示例使用 replaceError 操作符
let url = URL(string: "https://www.example.com/data")!
fetchDataFromURL(url: url)
// 用于在出现错误时,替换为默认的字符串 "Failed to load data"。
.replaceError(with: "Failed to load data")
// 订阅者用于接收和处理成功的值和错误,以及完成事件。
.sink(receiveCompletion: { completion in
switch completion {
case .finished:
print("Data fetching completed")
case .failure(let error):
print("Data fetching failed with error:", error)
}
}, receiveValue: { value in
print("Received data:", value)
})
.store(in: &cancellables)
输出结果
- 网络请求成功,输出:
Received data: Example Data
Data fetching completed
- 网络错误或者解析错误,由于使用了
replaceError(with:)
操作符,输出将会是:
Received data: Failed to load data
Data fetching completed