swiftUI的子视图中@StateObject和@ObservedObject有什么区别

问题描述

我创建了一个像这样的模型:

class TestModel: ObservableObject {
    @Published var num: Int = 0
}

模型用于“主页”视图和“主页”的子视图“ HomeSub”

struct Home: View {
    
    @StateObject var model = TestModel()
    
    var body: some View {
        NavigationView(content: {
            NavigationLink(destination: HomeSub(model: model)) { Text("\(model.num)") }
        })
    }
}
struct HomeSub: View {
   //1
    @StateObject var model = TestModel()
   //2
    @Observedobject var model = TestModel()

    var body: some View {
        vstack {
            Text("\(model.num)")
                .padding()
                .background(Color.red)
            Button("Add") {
                model.num += 1
            }
        }
        .onChange(of: model.num,perform: { value in
            print("homeSub: \(value)")
        })
        
    }
}

在HomeSub视图中,1和2有什么区别? 当我运行项目时,它们具有完全相同的行为。

解决方法

在撰写本文时,@StateObject@ObservedObject在子视图中都做相同的事情。但是,这都不对,因为他们不必要地创建新的TestModel只是为了扔掉它并用传入的值替换它。

编写子视图的正确方法是:

@ObservedObject var model: TestModel

在这种情况下,子视图中没有为model分配初始值,这意味着调用者将必须提供它。这正是您想要的。一个真理来源,即父视图中的model

此外,视图的状态变量(@State@StateObject)应为private,并始终标记为private。如果您这样做:

@StateObject private var model = TestModel()

在子视图中,您将无法从父视图传递模型,并且您会看到在这种情况下只能使用@ObservedObject


在进一步测试中,当Swift / SwiftUI编写为TestModel时似乎避免在子视图中创建@ObservedObject var model = TestModel(),但是语法仍然会误导读者,应该仍然是之所以写成@ObservedObject var model: TestModel,是因为它清楚表明model是从其他地方(即从父视图)初始化的。

,

它们几乎可以互换使用,并且在您的设置中创建同一模型的2个实例。

@StateObject的生命周期由SwiftUI管理,仅在iOS 14+中可用。

https://developer.apple.com/documentation/swiftui/stateobject

@ObservableObject的生命周期由开发人员管理(有时可以通过刷新View来无意重新初始化,因为它应该来自父View),它可以在iOS 13以上版本。

https://developer.apple.com/documentation/swiftui/managing-model-data-in-your-app

,

在这种情况下,最好在从父级注入值时使用@ObservedObject@StateObject旨在在View上独立保存一个对象(其生命周期由SwiftUI管理)。由于注射,这里不需要。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...