Swift中如何使用异步函数的完成处理程序版本?
问题
我有一个异步函数func doWork(id: String) async throws -> String,想从并发调度队列中调用它做测试,原本想这么写:
for i in 1...100 { queue.async { obj.doWork(id: "foo") { result, error in // 处理结果 } } }
这么写是因为queue.async { try await obj.doWork() }不被支持,会报错误:
Cannot pass function of type '@Sendable () async throws -> Void' to parameter expecting synchronous function type
但编译器并没有为doWork(id:)生成带完成处理程序的版本,不过在Objective-C里我可以用这个版本:[obj doWorkWithId: @"foo" completionHandler:^(NSString * val, NSError * _Nullable error) { ... }]。请问在Swift中怎么实现类似操作?
解决方法
1. 手动封装带完成回调的版本
给原异步函数写一个扩展,封装出适配GCD的带completionHandler的版本:
extension YourObjectType { func doWork(id: String, completionHandler: @escaping (String?, Error?) -> Void) { Task { do { let result = try await self.doWork(id: id) completionHandler(result, nil) } catch { completionHandler(nil, error) } } } }
之后就可以按你最初的写法在GCD队列中调用:
for i in 1...100 { queue.async { obj.doWork(id: "foo") { result, error in if let error = error { // 处理错误逻辑 print("执行失败:\(error)") return } if let result = result { // 处理结果逻辑 print("执行结果:\(result)") } } } }
2. 直接用Task适配GCD队列
如果不想额外封装,也可以在GCD的同步闭包内部启动Task来执行异步逻辑:
for i in 1...100 { queue.async { Task { do { let result = try await obj.doWork(id: "foo") // 处理结果 print("执行结果:\(result)") } catch { // 处理错误 print("执行失败:\(error)") } } } }
这种方式里,GCD的async保证闭包在指定队列启动,内部的Task则负责处理异步逻辑的调度。
补充说明
GCD的async方法仅接受同步闭包,你最初传入的async throws异步闭包类型不匹配,因此编译器报错。上述两种方案都是将异步逻辑包装成GCD可接受的同步闭包形式。
内容的提问来源于stack exchange,提问作者Dracula
相关产品推荐
相关产品推荐

