在SwiftUI App结构中使用@StateObject属性包装器的原因?

时间:2020-10-05 20:15:09

标签: swiftui

这来自有关SwiftUI App协议的Apple文档:

@main
struct Mail: App {
    @StateObject private var model = MailModel()

    var body: some Scene {
        WindowGroup {
            MailViewer()
                .environmentObject(model) // Passed through the environment.
        }
        Settings {
            SettingsView(model: model) // Passed as an observed object.
        }
    }
}

在这种情况下,为什么需要使用@StateObject propertyWrapper?为什么普通财产还不够?

我怀疑“ App”结构是一个配置对象,就像SwiftUI中的视图一样?而且我们不能指望一旦读取尸体就可以在周围徘徊的那个结构吗?正确吗?

2 个答案:

答案 0 :(得分:1)

根据Apple @StateObjectmodel中所做的保证

@StateObject private var model = MailModel()

仅创建一次。与@ObservedObject完全不同。因此,如果这对您不重要(或情况并非如此),并且您不需要在该级别进行观察,则可以使用常规属性声明。

答案 1 :(得分:0)

主要原因是进行预览,未初始化使用@StateObject初始化的模型。 WWDC 2020 Structure your app for SwiftUI previews 8:19

第二,模型发生了变化,@StateObject将使SwiftUI能够检测到变化并导致body被重新计算,因为模型是在体内引用(两次)的,SwiftUI通过依赖关系知道跟踪。这意味着将使用模型中的新数据重新创建MailViewerSettingsView。然后,如果这些View结构发生了任何变化,SwiftUI就会通过将新结构与先前返回的结构进行区分来检测到该变化,并使用需要进行的任何更新来更新屏幕,以使屏幕保持最新状态。

正如您所说,我们不能保证结构可以徘徊,实际上它们不是,它们是创建的,渲染的屏幕以及它们被扔掉了。这就是为什么我们使用属性包装器的原因,因此当再次创建该结构时,将为该属性使用相同的数据。在@StateObject的情况下,对象仅创建一次,这是第一次对第一个结构的主体进行计算。如果不再创建结构,例如如果if语句将其排除,则该对象为deinit。如果将来再次创建该结构,则将创建一个新对象,这对Views而言比对Apps而言更多。这意味着状态对象的生命周期与屏幕上显示的View的生命周期紧密相关。

如果我们要使用常规属性在SwiftUI结构上初始化对象,则每次重新创建结构时都会创建这些对象,这是一个堆分配,会占用RAM并减慢SwiftUI的使用,应不惜一切代价避免