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

iOS开发报错:无法将异步Throws函数传入同步参数类型

错误解析与修复:Cannot pass function of type '(Bool) async throws -> Void' to parameter expecting synchronous function type

错误含义

这个错误的核心是闭包类型不匹配:你传入的闭包包含了async throws类型的代码(比如try await URLSession.shared.data(from: url)),导致闭包整体类型变成了(Bool) async throws -> Void,但downloadFileFromS3的completion参数要求的是同步、无抛出的(Bool)->Void闭包,两者类型不兼容,因此编译器报错。

解决思路

最简洁的解决方式是把传统的Completion Handler风格代码迁移到Swift的Async/Await异步模型,避免嵌套闭包带来的类型冲突,同时让代码逻辑更清晰。

关键修改步骤

  1. 将downloadFileFromS3重构为异步抛出函数,替代原来的Completion Handler回调。
  2. 调整downloadAppThemeJson的逻辑,用Async/Await链式调用替代嵌套闭包,避免在同步闭包中写入异步代码。
  3. 修复错误处理逻辑,把吞掉错误的try?改为try,统一处理所有异常。

修改后的完整代码

重构后的S3下载函数

func downloadFileFromS3(client: String, fileName: String) async throws {
    let documentsUrl = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
    let downloadFileURL = documentsUrl.appendingPathComponent(fileName)
    
    let s3BucketName = Constants.UIFileLocation.s3BucketName + client
    let s3DownloadKeyName = fileName
    
    let expression = AWSS3TransferUtilityDownloadExpression()
    
    // 用withCheckedThrowingContinuation将Completion Handler转为Async/Await风格
    return try await withCheckedThrowingContinuation { continuation in
        let completionHandler: AWSS3TransferUtilityDownloadCompletionHandlerBlock = { task, location, data, error in
            DispatchQueue.main.async {
                do {
                    // 处理下载数据为空的情况
                    guard let data = data else {
                        let emptyError = NSError(domain: "S3DownloadError", code: -1, userInfo: [NSLocalizedDescriptionKey: "下载数据为空"])
                        continuation.resume(throwing: emptyError)
                        return
                    }
                    // 写入本地文件,抛出错误让上层处理
                    try data.write(to: downloadFileURL)
                    continuation.resume()
                } catch {
                    continuation.resume(throwing: error)
                }
            }
        }
        
        let transferUtility = AWSS3TransferUtility.default()
        transferUtility.downloadData(fromBucket: s3BucketName, key: s3DownloadKeyName, expression: expression, completionHandler: completionHandler)
            .continueWith { task in
                // 处理S3传输任务本身的错误
                if let error = task.error {
                    continuation.resume(throwing: error)
                }
                return nil
            }
    }
}

调整后的主题JSON下载与解析函数

func downloadAppThemeJson(completionHandler: @escaping(Bool) -> Void){
    Task {
        do {
            // 1. 异步从S3下载文件到本地
            try await downloadFileFromS3(client: self.selectedClient, fileName: Constants.ScreensUI.appInfo)
            
            // 2. 读取本地文件数据(直接用Data(contentsOf:),无需URLSession)
            let documentsUrl = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
            let fileUrl = documentsUrl.appendingPathComponent(Constants.ScreensUI.appInfo)
            let data = try Data(contentsOf: fileUrl)
            
            // 3. 解析为自定义模型
            let customModel = try JSONDecoder().decode(CustomModel.self, from: data)
            // 这里可以添加模型的后续处理逻辑,比如存储到全局变量或通知UI更新
            print("模型解析成功: \(customModel)")
            
            completionHandler(true)
        } catch {
            // 统一处理所有错误:S3下载、文件读写、JSON解析
            print("处理失败: \(error.localizedDescription)")
            completionHandler(false)
        }
    }
}

额外说明

  • 原代码中downloadAppThemeJson里的fileName变量未定义,修改后替换为Constants.ScreensUI.appInfo,避免编译错误。
  • 读取本地文件时使用Data(contentsOf:)替代URLSession.shared.data(from:),因为本地文件无需网络请求,前者更高效。
  • 所有错误都通过throws抛出,统一在catch块中处理,避免了try?吞掉错误导致的调试困难。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 14:27:49