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

Objective-C completion API如何通过async-await实现调用?

UIKit基于Completion的API转Async/Await的实现方式

UIKit中存在不少基于completion handler的经典API,比如UIApplication的open(_:options:completionHandler:),其原定义为:

func open(
    _ url: URL,
    options: [UIApplication.OpenExternalURLOptionsKey : Any] = [:],
    completionHandler completion: (@MainActor @Sendable (Bool) -> Void)? = nil
)

随着Swift结构化并发的引入,苹果为这类方法新增了async版本:

func open(
    _ url: URL, 
    options: [UIApplication.OpenExternalURLOptionsKey : Any] = [:]
) async -> Bool

苹果官方文档说明这类async/await绑定是通过固定算法自动生成的,但具体转换逻辑是怎样的?常见的猜测有两种:一是直接用continuation包装原有调用,二是采用更复杂的特殊实现。

实际实现方式

苹果确实是通过CheckedContinuation(或其变体)来完成这类自动转换的,具体逻辑大致如下:

  • 调用async版本方法时,系统会创建CheckedContinuation实例,挂起当前任务,等待completion handler触发;
  • 接着调用原有的带completion的API,传入一个闭包作为completion handler——这个闭包会在任务结束时被调用,通过continuation恢复挂起的任务,并将completion的参数(比如示例中的Bool结果)作为async方法的返回值传递;
  • 系统还会自动处理细节问题:比如保证continuation只被调用一次(避免任务悬挂)、处理上下文隔离(比如原API标注@MainActor时,async版本也会遵循主线程要求)、以及Sendable合规性检查。

你可以用手动模拟的代码来对应苹果自动生成的逻辑:

extension UIApplication {
    func open(_ url: URL, options: [UIApplication.OpenExternalURLOptionsKey : Any] = [:]) async -> Bool {
        await withCheckedContinuation { continuation in
            self.open(url, options: options) { success in
                continuation.resume(returning: success)
            }
        }
    }
}

这种自动转换能生效,是因为苹果的算法会识别符合特定模式的API:

  • 方法的最后一个参数是completion handler,闭包的参数对应async方法的返回值(若闭包有多个参数,async版本会返回元组);
  • 方法本身是异步执行的,且completion handler只会被调用一次。

这种实现既利用了Swift结构化并发的特性,又能最大程度复用原有API的底层逻辑,无需对核心功能做大幅改动。


内容的提问来源于stack exchange,提问作者Isaaс Weisberg

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 08:11:07