异步代码是否一定运行在其他线程?Swift @escaping闭包线程问题咨询
问题解答
1. 「异步代码必然运行在调用线程之外」的观点正误
这个观点完全错误。
异步的核心定义是「不阻塞当前调用线程的执行流,任务完成/回调执行的时机晚于当前函数返回」,和是否切换线程没有绑定关系:
- 典型的同线程异步场景:调用
DispatchQueue.main.async { ... }往主线程队列提交任务,这个任务是异步执行的(不会阻塞当前代码往下走,会等当前主线程空闲后再执行),但它的执行线程就是主线程本身,不会切换新线程。 - 是否切换线程只由任务提交的目标队列决定,和异步这个属性无关。
2. @escaping关键字的实际作用
@escaping和闭包的运行线程、同步/异步执行逻辑没有任何关系,它的唯一作用是向编译器标记:这个闭包的生命周期会超出当前接收它的函数的作用域,需要持有它到函数返回之后再调用。
你完全可以自由决定逃逸闭包的调用线程:既可以在后台线程调用,也可以在主线程调用,甚至可以和调用线程完全一致。
3. 布局修改报错的原因
你遇到的报错和@escaping本身没有任何关联,问题出在CNContactStore.requestAccess(for:completionHandler:)这个系统API的completionHandler默认会在后台全局队列执行,你直接在这个回调里修改UI/布局就触发了主线程校验。
所有系统API的回调线程都需要看对应文档的说明,没有统一规则:部分系统API会保证回调在主线程执行,也有大量类似CNContactStore的API会默认把回调派发到后台队列执行,这种场景下你如果要做UI操作,必须手动把代码派发到主线程:
CNContactStore().requestAccess(for: .contacts) { granted, error in DispatchQueue.main.async { // 在这里执行UI修改/布局调整逻辑 } }
内容的提问来源于stack exchange,提问作者daniel
相关产品推荐
相关产品推荐

