Swift报错:无法将异步闭包传入同步类型的completion参数
错误原因分析
- 闭包类型不匹配:你在
sendMessage2的completion闭包中使用了await MainActor.run,这会让闭包自动变为异步函数类型(OpenAIChatResponse) async -> Void,但sendMessage定义的completion参数是同步类型(_ response: OpenAIChatResponse) -> Void,两者类型不匹配导致报错。 - 冗余异步嵌套:
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
相关产品推荐
相关产品推荐

