互操作 Async/await、@MainActor 和 DispatchQueue.main.async
Interoperating Async/await, @MainActor and DispatchQueue.main.async
假设我有这个代码:
class Presenter {
var viewToUpdate: UIView!
func updateUI() {
viewToUpdate.backgroundColor = .red
}
}
class ShinyNewAsyncAwaitClass {
func doAsyncAwaitThing() async {
// make network call or something
}
}
class OtherClassThatICantUpdateToAsyncAwaitYet {
func doOldClosureBasedThing(completion: @escaping () -> Void) {
// make network call or something
completion()
}
}
class TheClassThatUsesAllThisStuff {
var newClass: ShinyNewAsyncAwaitClass!
var oldClass: OtherClassThatICantUpdateToAsyncAwaitYet!
var presenter: Presenter!
func doSomethingWithNewClass() {
Task {
await self.newClass.doAsyncAwaitThing()
// ---->>> What do I do here? <<<<----
await self.presenter.updateUI()
}
}
func doSomethingWithOldClass() {
oldClass.doOldClosureBasedThing {
DispatchQueue.main.async {
self.presenter.updateUI()
}
}
}
func justUpdateTheView() {
self.presenter.updateUI()
}
}
总之,我有3个类。一个我可以更新到 async/await,另一个我不能,一个同时使用两者。两者都需要访问更新 UI 的函数,都需要在主线程上访问该函数。
我在某处看到我可以将@MainActor 添加到 updateUI
函数,但是在我已经在主线程上并且我只想调用 updateUI
的情况下,例如 justUpdateTheView
我得到这个错误:
Call to main actor-isolated instance method 'updateUI()' in a synchronous nonisolated context
Add '@MainActor' to make instance method 'justUpdateTheView()' part of global actor 'MainActor'
我无法将 justUpdateTheView
定义为 @MainActor,因为我们正在尝试将我们的项目缓慢更新为新的并发性内容,这会导致需要进行更改的连锁反应。
做什么最好?我可以这样做吗:
func doSomethingWithNewClass() {
Task {
await self.newClass.doAsyncAwaitThing()
DispatchQueue.main.async {
self.presenter.updateUI()
}
}
}
可以编译,但是有什么需要注意的地方吗?
您可以对 运行 MainActor
上的 UI 代码执行类似的操作:
func doSomethingWithNewClass() {
Task {
await self.newClass.doAsyncAwaitThing()
await MainActor.run {
self.presenter.updateUI()
}
}
}
假设我有这个代码:
class Presenter {
var viewToUpdate: UIView!
func updateUI() {
viewToUpdate.backgroundColor = .red
}
}
class ShinyNewAsyncAwaitClass {
func doAsyncAwaitThing() async {
// make network call or something
}
}
class OtherClassThatICantUpdateToAsyncAwaitYet {
func doOldClosureBasedThing(completion: @escaping () -> Void) {
// make network call or something
completion()
}
}
class TheClassThatUsesAllThisStuff {
var newClass: ShinyNewAsyncAwaitClass!
var oldClass: OtherClassThatICantUpdateToAsyncAwaitYet!
var presenter: Presenter!
func doSomethingWithNewClass() {
Task {
await self.newClass.doAsyncAwaitThing()
// ---->>> What do I do here? <<<<----
await self.presenter.updateUI()
}
}
func doSomethingWithOldClass() {
oldClass.doOldClosureBasedThing {
DispatchQueue.main.async {
self.presenter.updateUI()
}
}
}
func justUpdateTheView() {
self.presenter.updateUI()
}
}
总之,我有3个类。一个我可以更新到 async/await,另一个我不能,一个同时使用两者。两者都需要访问更新 UI 的函数,都需要在主线程上访问该函数。
我在某处看到我可以将@MainActor 添加到 updateUI
函数,但是在我已经在主线程上并且我只想调用 updateUI
的情况下,例如 justUpdateTheView
我得到这个错误:
Call to main actor-isolated instance method 'updateUI()' in a synchronous nonisolated context
Add '@MainActor' to make instance method 'justUpdateTheView()' part of global actor 'MainActor'
我无法将 justUpdateTheView
定义为 @MainActor,因为我们正在尝试将我们的项目缓慢更新为新的并发性内容,这会导致需要进行更改的连锁反应。
做什么最好?我可以这样做吗:
func doSomethingWithNewClass() {
Task {
await self.newClass.doAsyncAwaitThing()
DispatchQueue.main.async {
self.presenter.updateUI()
}
}
}
可以编译,但是有什么需要注意的地方吗?
您可以对 运行 MainActor
上的 UI 代码执行类似的操作:
func doSomethingWithNewClass() {
Task {
await self.newClass.doAsyncAwaitThing()
await MainActor.run {
self.presenter.updateUI()
}
}
}