PromiseKit错误处理策略:从基础到高级异常捕获
【免费下载链接】PromiseKit Promises for Swift & ObjC. 项目地址: https://gitcode.com/gh_mirrors/pr/PromiseKit
你是否还在为异步代码中的错误处理而头疼?是否经常遇到错误传递混乱、异常捕获不完整的问题?本文将系统介绍PromiseKit中的错误处理机制,从基础的错误类型定义到高级的异常捕获策略,帮助你构建健壮的异步代码。读完本文,你将掌握PromiseKit错误处理的核心方法,包括错误类型识别、链式捕获、恢复策略以及取消操作处理等实用技巧。
错误类型基础
PromiseKit定义了一套完整的错误处理体系,核心错误类型为PMKError枚举,定义在Sources/Error.swift文件中。该枚举包含多种常见错误场景,例如无效调用约定、返回自身 promise、输入参数错误等。
public enum PMKError: Error {
case invalidCallingConvention // 无效的调用约定,如 completionHandler 同时返回 nil 和错误
case returnedSelf // handler 返回自身 promise(违反 Promises/A+ 规范)
case badInput // when()、race() 等函数接收到无效参数
case cancelled // 操作已取消
case compactMap(Any, Any.Type) // compactMap 返回 nil
case emptySequence // 请求序列的 first/last 值但序列为空
case noWinner // race(fulfilled:) 中所有 promise 均被拒绝
}
除了框架定义的错误类型,PromiseKit还提供了CancellableError协议,用于标识可取消操作产生的错误。通过扩展Error类型,PromiseKit实现了对系统常见取消错误的统一识别,包括URLError.cancelled、CocoaError.userCancelled等。
基础错误捕获
PromiseKit的错误捕获通过catch方法实现,该方法定义在Sources/Catchable.swift中,作为CatchMixin协议的扩展方法。基础用法如下:
fetchData()
.then { process($0) }
.catch { error in
print("捕获到错误: \(error.localizedDescription)")
}
catch方法默认不会捕获取消类型错误,这是因为取消操作在很多场景下不应被视为错误。如果需要捕获包括取消在内的所有错误,可以指定CatchPolicy.allErrors策略:
fetchData()
.catch(policy: .allErrors) { error in
if error.isCancelled {
print("操作已取消")
} else {
print("捕获到错误: \(error)")
}
}
错误恢复策略
当异步操作失败时,有时我们希望提供替代结果或重试机制,这可以通过recover方法实现。recover允许你在错误发生时返回一个新的promise,从而恢复整个异步链条。
基本恢复示例
CLLocationManager.requestLocation()
.recover { error -> Promise<CLLocation> in
// 仅处理特定错误,其他错误继续传播
guard error == CLError.unknownLocation else { throw error }
return .value(CLLocation.savannah) // 返回默认位置
}
.done { location in
print("使用位置: \(location)")
}
.catch { error in
print("无法获取位置: \(error)")
}
重试机制实现
结合recover和延迟操作,可以实现失败重试逻辑。以下是一个最多重试3次的示例:
func attempt<T>(maximumRetryCount: Int = 3, delayBeforeRetry: DispatchTimeInterval = .seconds(2), _ body: @escaping () -> Promise<T>) -> Promise<T> {
var attempts = 0
func attempt() -> Promise<T> {
attempts += 1
return body().recover { error -> Promise<T> in
guard attempts < maximumRetryCount else { throw error }
return after(delayBeforeRetry).then(attempt)
}
}
return attempt()
}
// 使用示例
attempt(maximumRetryCount: 3) {
flakeyNetworkRequest()
}.then { result in
print("请求成功: \(result)")
}.catch { error in
print("3次尝试后仍失败: \(error)")
}
高级错误处理模式
选择性错误处理
在复杂场景中,我们可能需要对不同类型的错误采取不同处理策略。可以通过类型转换或错误代码判断来实现:
fetchData()
.catch { error in
if let networkError = error as? NetworkError {
handleNetworkError(networkError)
} else if error.isCancelled {
handleCancellation()
} else if let pmkError = error as? PMKError {
handlePMKError(pmkError)
} else {
handleGenericError(error)
}
}
确保资源释放
ensure方法无论promise是成功还是失败都会执行,非常适合用于资源清理操作:
let connection = openDatabaseConnection()
fetchData()
.then { process($0) }
.ensure {
connection.close() // 无论成功失败都会关闭连接
}
.catch { error in
print("处理错误: \(error)")
}
如果清理操作本身也是异步的,可以使用ensureThen方法,它会等待返回的Guarantee完成后再继续:
setup()
.then { doWork() }
.ensureThen {
teardown() // 返回 Guarantee<Void>
}
.catch { error in
print("处理错误: \(error)")
}
取消操作处理
PromiseKit通过特殊的PMKError.cancelled错误类型支持取消操作。实现可取消的异步操作通常需要返回一个包含取消函数的元组:
func fetchWithCancel() -> (promise: Promise<Data>, cancel: () -> Void) {
let task = URLSession.shared.dataTask(with: url)
var isCancelled = false
let promise = Promise<Data> { seal in
task.completionHandler = { data, _, error in
if isCancelled {
seal.reject(PMKError.cancelled)
return
}
if let error = error {
seal.reject(error)
} else {
seal.fulfill(data ?? Data())
}
}
task.resume()
}
let cancel = {
isCancelled = true
task.cancel()
}
return (promise, cancel)
}
// 使用示例
let (fetchPromise, cancelFetch) = fetchWithCancel()
fetchPromise
.done { data in print("获取数据: \(data)") }
.catch { error in
if error.isCancelled {
print("请求已取消")
} else {
print("请求失败: \(error)")
}
}
// 需要时取消请求
cancelFetch()
错误处理最佳实践
1. 避免空catch块
空的catch块会隐藏潜在问题,至少应该记录错误:
// 不推荐
.catch {}
// 推荐
.catch { error in
logError("未处理的错误: \(error)")
}
2. 使用cauterize处理已知无害错误
对于确定无需处理的错误,可以使用cauterize()方法明确表达意图:
// 已知此错误无害,无需处理
UIView.animate(.promise, duration: 0.3) {
view.alpha = 0
}.cauterize()
3. 错误恢复粒度控制
在进行错误恢复时,应尽量精确匹配需要恢复的错误类型,避免意外恢复:
.recover { error in
// 仅恢复网络超时错误
guard case .networkError(let code) = error, code == .timeout else {
throw error // 其他错误继续传播
}
return fetchFromCache() // 返回缓存数据作为替代
}
4. 错误信息传递
自定义错误类型时,应遵循LocalizedError协议,提供有意义的错误描述:
enum AppError: Error, LocalizedError {
case invalidUserID(String)
var errorDescription: String? {
switch self {
case .invalidUserID(let id):
return "无效的用户ID: \(id),格式应为UUID"
}
}
}
总结
PromiseKit提供了全面的错误处理机制,从基础的错误捕获到高级的恢复策略,能够满足各种异步场景的需求。关键要点包括:
- 使用
PMKError和CancellableError识别不同类型的错误 - 通过
catch方法捕获错误,注意默认不处理取消类型错误 - 使用
recover实现错误恢复,返回替代结果或重试操作 - 利用
ensure和ensureThen确保资源正确释放 - 实现可取消操作时遵循PromiseKit的取消模式
合理运用这些机制,可以显著提升异步代码的健壮性和可维护性。更多错误处理模式和最佳实践,请参考官方文档Documentation/CommonPatterns.md。
【免费下载链接】PromiseKit Promises for Swift & ObjC. 项目地址: https://gitcode.com/gh_mirrors/pr/PromiseKit
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



