2

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

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 有什么区别?当我运行该项目时,它们的行为完全相同。

4

3 回答 3

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正在从某个地方初始化else(即从父视图)。

于 2020-10-27T10:44:36.133 回答
0

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

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

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

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

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

于 2020-10-27T11:22:25.223 回答
0

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

于 2020-10-27T11:28:11.800 回答