概览
在使用多个Actor 共同实现同步功能的时候,我们往往会看到如下使用场景:
Actor A 必须在主线程上运行,Actor B可以在任意线程上运行,但需要适时的调用 Actor A 中的方法。
在这种情况下,我们会遇到如下代码:
如上代码所示,需要在 worker.doing() 调用前加上 await 关键字,毕竟此时可能会发生任务挂起和切换。
其实,我们还有一种更好的方法来完成 working.doing() 方法的调用,下面就让我们来看看如何操作吧。 😉
代码解析
示例的源代码如下,非常简单:
@MainActor
class Worker {
func doing() {
print("important working...")
}
}
actor Superman {
unowned let worker: Worker!
init(worker: Worker) {
self.worker = worker
}
func todo() {
Task {
await worker.doing()
}
}
}
我们看到 Worker 类必须在主线程上保持同步,而 Superman 可以在任意线程上进行同步,但需要调用 Worker 中的 doing() 方法。
除了使用 await 关键字修饰 worker.doing() 方法之外,我们还可以显式让 Swift 明白我们的 Task 闭包代码必须在主线程上执行。
解决之道
在 Swift 推出新 async/await 并发模型的同时,Apple 同样对闭包调用做了升级。
现在,我们可以在闭包中添加新的 @MainActor 关键字来明确闭包内容必须在主线程上运行。
于是乎,上面的代码就可以修改为如下形式:
actor Superman {
unowned let worker: Worker!
init(worker: Worker) {
self.worker = worker
}
func todo() {
Task { @MainActor in
worker.doing()
}
}
}
我们成功的“摆脱”了 await 关键字,并且让意图更加明显。
总结
其实,我们并没有真正摆脱 await 关键字,任务切换仍然会和原来一样发生,只不过我们不再关心,只要看到闭包中的 @MainActor 关键字,一切都了然了,不是吗?
感谢观赏,再会 ! 😃