You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为带回调的Swift函数封装async-await包装器并适配现有代码

问题核心

你的代码无法正常工作有两个关键原因:

  1. 异步回调的completion闭包未声明为可抛出,你在其中执行throw error完全无效,且异步回调的错误无法传递到外部同步函数的调用层级。
  2. 封装的save函数是同步返回Bool,但内部调用的是异步操作,这个返回值根本无法反映异步操作的最终状态。
两种可行解决方案

根据你需要获取操作成功/失败状态及错误信息的需求,提供两种适配方式:

方案一:用Result回调传递结果(适配现有回调代码)

如果暂时不想引入async-await,可以给封装函数添加一个带Result类型的回调,将异步操作的结果传递出去:

先补全必要的类型别名(如果项目中未定义):

typealias CountHandler = (Int) -> Void
typealias ProgressHandler = (String) -> Void
typealias SaveCompletion = (Result<Void, Error>) -> Void

修改后的封装函数:

private func save(records: [CKRecord], handler: ProgressHandler?, completion: @escaping SaveCompletion) {
    save(records: records, recordIDsToDelete: []) { count in
        handler?("Saving\n\(count)\nrecords.")
    } completion: { _, _, _, error in
        if let err = error {
            completion(.failure(err))
        } else {
            completion(.success(()))
        }
    }
}

调用示例:

save(records: yourRecordList, handler: { progressText in
    // 此处可更新进度UI或打印日志
    print(progressText)
}) { result in
    switch result {
    case .success:
        print("保存成功")
    case .failure(let error):
        print("保存失败:\(error.localizedDescription)")
    }
}

方案二:提前适配async-await(推荐,契合你未来的重写计划)

直接将封装函数改为async-await形式,既能满足当前接入需求,也能为未来的重写工作无缝衔接:

private func save(records: [CKRecord], handler: ProgressHandler?) async throws {
    try await withCheckedThrowingContinuation { continuation in
        save(records: records, recordIDsToDelete: []) { count in
            handler?("Saving\n\(count)\nrecords.")
        } completion: { _, _, _, error in
            if let err = error {
                continuation.resume(throwing: err)
            } else {
                continuation.resume()
            }
        }
    }
}

调用示例(需在async上下文执行,用Task包裹):

Task {
    do {
        try await save(records: yourRecordList) { progressText in
            print(progressText)
        }
        print("保存成功")
    } catch {
        print("保存失败:\(error.localizedDescription)")
    }
}
方案选择建议
  • 若现有代码完全基于回调风格,不想改动调用逻辑,选择方案一。
  • 若想提前适配Swift现代异步编程规范,且未来计划重写为async-await,优先选择方案二,一步到位。

内容的提问来源于stack exchange,提问作者kunass2

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 02:06:25