DispatchQueue的闭包是 @Sendable的,它如何访问由主Actor隔离的值?
先尝试这段代码:
func viewDidLoad() {
DispatchQueue.global().async {
self.view.backgroundColor = red
}
}
这在Swift 6中显然会失败,因为闭包是 @Sendable,也就是说它可以在后台线程中被调用,因此无法访问被主actor隔离的值(self.view)
有趣的部分在这里:
func viewDidLoad() {
DispatchQueue.main.async {
self.view.backgroundColor = red
}
}
这段代码可以正常编译。
然而,若你查看API,DispatchQueue.global() 和DispatchQueue.main是相同类型(DispatchQueue),它们都接受一个 @Sendable 闭包。主队列会不会神奇地把 @Sendable 闭包变成一个 @MainActor 闭包?
解决方案
DispatchQueue.main.async 只是被编译器硬编码的一个特例。这个检查由函数 isMainDispatchQueueMember 来完成,它只是查看AST,看看是否匹配“DispatchQueue.main”。如果匹配,编译器最终会把闭包的类型调整为对主actor进行隔离,从而使闭包具备可发送性。
你可以从 这一行 开始,跟踪编译器的源代码,看看它最终如何达到 applyUnsafeConcurrencyToParameterType。
因为这只是一个AST检查,以不同但等效的方式写 DispatchQueue.main 都会导致检查失败,并产生你预期的警告/错误。
let queue = DispatchQueue.main
queue.async {
mainActorFunc() // warning
}
typealias DP = DispatchQueue
DP.main.async {
mainActorFunc() // warning
}
另一方面,如果你定义一个名为 DispatchQueue 的自定义类型,并为它添加一个 main 属性和一个 async 方法,那么就不会有任何警告!
struct DispatchQueue {
static let main = DispatchQueue()
func async(block: @Sendable () -> Void) {
}
}
DispatchQueue.main.async {
mainActorFunc() // totally fine by the compiler
}
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。