我正在尝试使用@Observable,但我注意到View并没有使用@State来保持ViewModel。每当 ContentView 中发生变化时,就像 TextField 中的字母一样,ViewModel 就会调用 init。 为什么会发生这种情况,而不是以 ObservableObject 的旧方式发生? 如果有人可以向我解释这是如何工作的以及我如何做得更好,我将非常感激。
示例:
struct ContentView: View {
@State var text = ""
var body: some View {
TextField("Enter text", text: $text)
SubView()
}
}
@Observable class SubViewModel {
var text: String = "Hello, World!"
init() {
// -> reload
print("init SubViewModel")
}
}
struct SubView: View {
@State private var viewModel: SubViewModel
init() {
_viewModel = State(wrappedValue: SubViewModel())
}
var body: some View {
Text(viewModel.text)
}
}
老方法
class SubViewModel: ObservableObject {
@Published var text: String = "Hello, World!"
init() {
// -> doesn't reload
print("init SubViewModel")
}
}
struct SubView: View {
@StateObject private var viewModel: SubViewModel
init() {
_viewModel = StateObject(wrappedValue: SubViewModel())
}
var body: some View {
Text(viewModel.text)
}
}
根据文档管理数据,使用
@Observable class
,在视图中形成对可观察数据模型对象的依赖,并且
“当跟踪的属性发生变化时,SwiftUI 会更新视图。如果其他属性发生变化而主体不读取,则视图不受影响并避免不必要的更新。”
避免当
SubView
中只有 text
时重新初始化 TextField
已更改,请尝试此方法,将 SubViewModel
声明移至 ContentView
并将其传递给 SubView
.
struct ContentView: View {
@State private var text = ""
@State private var viewModel = SubViewModel() // <-- here, source of data truth
var body: some View {
TextField("Enter text", text: $text)
SubView(viewModel: viewModel) // <-- here
}
}
@Observable class SubViewModel {
var text: String = "Hello, World!"
init() {
print("---> init SubViewModel")
}
}
struct SubView: View {
let viewModel: SubViewModel // <-- here
var body: some View {
Text(viewModel.text)
}
}