Swift escaping closures(逃逸闭包)异步场景使用疑问咨询
逃逸闭包异步场景疑问解答
你已知的逃逸闭包定义翻译为:如果一个闭包作为参数被传入函数,且在函数返回之后才被调用,这个闭包就是逃逸闭包
你对异步场景的疑惑本质是没有理清函数生命周期和异步闭包调度时机的先后关系:
- 普通同步函数的生命周期从调用启动开始,到执行完所有内部同步逻辑、返回结果结束,运行结束后函数的局部作用域会直接销毁。
- 当你在函数内部调用
Dispatch.main.async{}、发起网络请求这类异步操作时,函数仅仅完成了「提交异步任务、持有传入的闭包」的操作,不会等待异步闭包执行完成就会直接走完内部逻辑返回。
也就是说异步场景下,闭包的执行时机必然晚于函数的返回时机,完全符合逃逸闭包的判定规则,和异步操作本身的耗时长短没有关系。哪怕你提交的异步闭包只是执行一行简单的打印逻辑,只要是异步调度,函数都会在闭包执行前返回,闭包自然就逃出了函数的作用域生命周期。
常见误区说明
很多人会误以为是多线程运行导致闭包逃逸,本质和线程无关,核心判定条件始终是「闭包调用时机是否晚于函数返回」:比如你把传入的闭包赋值给全局变量,哪怕后续还是在当前线程调用这个闭包,只要调用动作发生在函数返回之后,这个闭包依然属于逃逸闭包。
我们可以用一段Swift代码示例更直观理解:
// 模拟异步请求函数 func requestUserData(completion: @escaping (String) -> Void) { // 发起网络请求,resume方法仅将请求加入系统调度,不会等待请求返回 URLSession.shared.dataTask(with: URL(string: "https://example.com/user")!) { data, _, _ in // 网络请求回调触发时,requestUserData函数早已执行完成并返回 let userName = String(data: data ?? Data(), encoding: .utf8) ?? "" completion(userName) }.resume() // 执行到这一行,函数直接返回,completion闭包还未被调用 }
内容的提问来源于stack exchange,提问作者mendokusai
相关产品推荐
相关产品推荐

