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

Swift报错:无法将异步闭包传入同步类型的completion参数

错误原因分析
  1. 闭包类型不匹配:你在sendMessage2的completion闭包中使用了await MainActor.run,这会让闭包自动变为异步函数类型(OpenAIChatResponse) async -> Void,但sendMessage定义的completion参数是同步类型(_ response: OpenAIChatResponse) -> Void,两者类型不匹配导致报错。
  2. 冗余异步嵌套:sendMessage本身标记为async,但内部又嵌套Task,外层的do-catch无法捕捉内部Task的错误(Task会脱离当前异步上下文),属于无效的错误处理逻辑。

修复方案

方案一:重构为纯Async/Await写法(推荐,符合Swift现代异步编程规范)

1. 修改sendMessage函数,移除completion,直接返回结果

@MainActor func sendMessage(messages: [Message]) async throws -> OpenAIChatResponse {
    let openAIMessages = messages.map { OpenAIChatMessage(role: $0.role, content: $0.content) }
    let body = OpenAIChatBody(model: "gpt-3.5-turbo", messages: openAIMessages)
    
    guard let endpointUrl = endpointUrl else {
        throw NetworkError.badUrl
    }
    
    var request = URLRequest(url: endpointUrl)
    request.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
    request.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Accept")
    request.httpMethod = "POST"
    request.httpBody = try JSONEncoder().encode(body)
    request.setValue("Bearer \(Constants.openAIApiKey)", forHTTPHeaderField: "Authorization")
    
    let (data, response) = try await URLSession.shared.data(for: request)
    
    // 校验响应有效性
    guard let httpResponse = response as? HTTPURLResponse else {
        throw NetworkError.badResponse
    }
    guard 200...299 ~= httpResponse.statusCode else {
        throw NetworkError.badStatus
    }
    
    return try JSONDecoder().decode(OpenAIChatResponse.self, from: data)
}

2. 修改sendMessage2函数,直接使用Async/Await处理结果

func sendMessage2(myMessage: String) {
    let newMessage = Message(id: UUID(), role: .user, content: myMessage, createAt: Date())
    messages.append(newMessage)
    
    Task {
        do {
            let response = try await openAIService.sendMessage(messages: messages)
            
            guard let receivedOpenAIMessage = response.choices?.first?.message else {
                return
            }
            let receivedMessage = Message(id: UUID(), role: receivedOpenAIMessage.role, content: receivedOpenAIMessage.content, createAt: Date())
            
            await MainActor.run {
                messages.append(receivedMessage)
            }
        } catch NetworkError.badUrl {
            print("URL创建出错")
        } catch NetworkError.badResponse {
            print("未获取到有效响应")
        } catch NetworkError.badStatus {
            print("响应状态码非2xx")
        } catch NetworkError.failedToDecodeResponse {
            print("响应解析失败")
        } catch {
            print("数据下载出错")
        }
    }
}

方案二:坚持使用Completion Handler写法(不推荐,但兼容原有逻辑)

1. 修改sendMessage函数,移除async标记,用Result类型传递结果

@MainActor func sendMessage(messages: [Message], completion: @escaping (Result<OpenAIChatResponse, Error>) -> Void) {
    let openAIMessages = messages.map { OpenAIChatMessage(role: $0.role, content: $0.content) }
    let body = OpenAIChatBody(model: "gpt-3.5-turbo", messages: openAIMessages)
    
    guard let endpointUrl = endpointUrl else {
        completion(.failure(NetworkError.badUrl))
        return
    }
    
    var request = URLRequest(url: endpointUrl)
    request.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
    request.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Accept")
    request.httpMethod = "POST"
    
    do {
        request.httpBody = try JSONEncoder().encode(body)
    } catch {
        completion(.failure(error))
        return
    }
    
    request.setValue("Bearer \(Constants.openAIApiKey)", forHTTPHeaderField: "Authorization")
    
    Task {
        do {
            let (data, response) = try await URLSession.shared.data(for: request)
            
            guard let httpResponse = response as? HTTPURLResponse else {
                throw NetworkError.badResponse
            }
            guard 200...299 ~= httpResponse.statusCode else {
                throw NetworkError.badStatus
            }
            
            let responseData = try JSONDecoder().decode(OpenAIChatResponse.self, from: data)
            completion(.success(responseData))
        } catch {
            completion(.failure(error))
        }
    }
}

2. 修改sendMessage2函数,同步闭包内嵌套Task处理UI更新

func sendMessage2(myMessage: String) {
    let newMessage = Message(id: UUID(), role: .user, content: myMessage, createAt: Date())
    messages.append(newMessage)
    
    openAIService.sendMessage(messages: messages) { result in
        switch result {
        case .success(let response):
            guard let receivedOpenAIMessage = response.choices?.first?.message else {
                return
            }
            let receivedMessage = Message(id: UUID(), role: receivedOpenAIMessage.role, content: receivedOpenAIMessage.content, createAt: Date())
            
            // 嵌套Task在主线程更新UI,避免闭包变为异步类型
            Task { @MainActor in
                messages.append(receivedMessage)
            }
        case .failure(let error):
            switch error {
            case NetworkError.badUrl:
                print("URL创建出错")
            case NetworkError.badResponse:
                print("未获取到有效响应")
            case NetworkError.badStatus:
                print("响应状态码非2xx")
            case NetworkError.failedToDecodeResponse:
                print("响应解析失败")
            default:
                print("数据下载出错")
            }
        }
    }
}

内容的提问来源于stack exchange,提问作者Mr. Man

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 19:39:51