互操作 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()
        }
    }
}