SwiftUI视图模型为什么应该用@MainActor进行注释?

8
我一直在关注苹果的WWDC21会议上与并发相关的讲座,以及阅读了大量有关苹果并发更新的文章;然而,我无法理解一件事:为什么人们要提供建议,让您使用@MainActor对视图模型进行注释?从我所了解的情况来看,通过将视图模型属性设置为视图中的@StateObject@ObservedObject,它会自动变为@MainActor。那么,如果是这样的话,为什么人们仍然建议对视图模型进行@MainActor注释呢?
为了更好地理解背景,这里是我阅读过的一些文章:
  1. https://www.hackingwithswift.com/quick-start/concurrency/understanding-how-global-actor-inference-works
  2. https://www.hackingwithswift.com/books/concurrency/how-to-use-mainactor-to-run-code-on-the-main-queue
  3. https://peterfriese.dev/swiftui-concurrency-essentials-part1/
第一个链接的摘录如下:

任何使用带有@MainActor属性包装器的结构体或类都将自动成为@MainActor。这就是使得在SwiftUI视图中使用@StateObject和@ObservedObject能够传达主actor特性的原因 - 如果您在SwiftUI视图中使用这两个属性包装器之一,则整个视图也会成为@MainActor。

第二个链接的摘录如下:

每当您在视图内部使用@StateObject或@ObservedObject时,Swift都会确保整个视图在主actor上运行,以便您不会意外地以危险的方式尝试发布UI更新。更好的是,无论您使用什么属性包装器,SwiftUI视图的body属性始终在主actor上运行。

那么这是否意味着您不需要显式地向可观察对象添加@MainActor?嗯,不是-使用这些类仍然有好处,尤其是如果它们正在使用async / await来执行自己的异步工作(例如从服务器下载数据)。

总的来说,如果所有东西都会自动处理,我对这些建议感到有点困惑。尤其是因为我不知道在SwiftUI中有哪种情况下您会有一个不是@ObservableObject的视图模型。

与第一个问题相关的我的最后一个问题是:如果@StateObject@ObservedObject自动使视图成为@MainActor,那么@EnvironmentObject是否也会使视图成为@MainActor

为了支持这个问题,我打算使用.environmentObject(...)将以下类注入到环境中:

@MainActor
class UserSettings: ObservableObject {
    @Published var flowUser: FlowUser?
    
    init(flowUser: FlowUser? = nil) {
        self.flowUser = flowUser
    }
}

以下是我其中一个视图的视图模型:
@MainActor
class CatalogViewModel: ObservableObject {
    @Published var flowUser: FlowUser?
    
    init(flowUser: FlowUser?) {
        self.flowUser = flowUser
    }
}

正如您所看到的,我已经使两个类都成为@ObservableObjects,因此我觉得应该能够删除@MainActor注释。

非常感谢您的帮助!感谢您抽出时间阅读!


2
他们(发布)更新UI(在大多数情况下),UI 必须(!)仅在主队列上更新。 - Asperi
如果你想知道是否可以删除@MainActor属性,为什么不尝试将其删除并查看会发生什么呢? - matt
在SwiftUI中,我们不使用视图模型对象(这就是View结构体的作用),通过@StateObject创建一个视图模型对象将会滥用它的设计。 - malhal
2
“@malhal说‘我们在SwiftUI中不使用视图模型对象’并不是真的,如果你不使用ViewModels并不意味着没有人在使用。我见过的大多数SwiftUI应用程序都是MVVM架构…” - kironet
@kironet,随着时间的推移,它们会逐渐学习View结构,因此你会看到越来越少的内容。 - malhal
1个回答

5

@ObservedObject或其他并不会使它成为主要角色。因此,你的说法是不正确的。

请参见https://developer.apple.com/videos/play/wwdc2021/10019/第22分钟左右enter image description here

根据我所读的,将视图模型属性作为@StateObject或@ObservedObject放在视图中,它会自动变成@MainActor。


1
事实上,属性包装器今天就能影响演员隔离。但是,幸运的是,这种情况正在改变,因为它已经引起了很多混乱。https://github.com/apple/swift-evolution/blob/main/proposals/0401-remove-property-wrapper-isolation.md - Mattie

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接