如何在 MainActor 中使用 URLSession

How to use URLSession in MainActor

我有一个 ViewModel@MainActor 隔离,我假设这个 ViewModel class 的每个部分都应该 运行 在主要演员身上(主线程),对吧?

那么问题来了,URLSession.shared.data的异步调用呢?

它也在 main thread 上 运行 吗?这不是一个糟糕的做法吗?

@MainActor
class ViewModel {
    @Published var name: String = ""
    
    func fetchName() async {
        guard let (data, _) = try? await URLSession.shared.data(from: URL(string: "http://....")!),
              let response = try? JSONDecoder().decode(Response.self, from: data) else {
            return
        }
        
        self.name = response.name
    }
}

Does it also run on main thread

没有。这就是 await 的全部意义所在。在那一刻,系统可以在您不知情或不关心的情况下将上下文切换到后台线程。此外,在 await 你的代码 暂停而不阻塞 — 这意味着当你等待下载时,主线程可以自由地做其他工作,用户可以与您的应用程序等。别担心,开心。

问题不在于您 awaitURLSession 代码。 运行 在由 URLSession 管理的单独线程上。每当您看到 await,这意味着当前执行在异步任务 运行 时被挂起,并且当前 actor 可以空闲 运行 其他代码。一切顺利。

唯一潜在的问题是 运行 同步在主要角色上的代码(即,除了我们 await 之外的所有内容)。在这种情况下,唯一相关的部分是代码 await 之后 ,在所谓的“延续”中。

在这种情况下,延续包括 JSON 的 decode 和 属性 的更新。这是适度的,你一般都很好 运行宁对主要演员。

但是如果续集包含任何更实质性的东西(例如解码许多兆字节的 JSON 或解码图像等),那么您可能希望将其从主要演员身上移开。但在这种情况下,你很好。

有关详细信息,请参阅 WWDC 2021 视频 Swift concurrency: Behind the scenes