我想让一个选择器使用SwiftUI,当我在ChildView中更改值时,它不会更改,并调用ChildView init。
class ViewModel: ObservableObject {
@Published var value: Int
init(v: Int) {
self.value = v
}
}
struct ChildView: View {
@Binding var value: Int
@ObservedObject var vm = ViewModel(v: 0)
init(value: Binding<Int>) {
self._value = value
print("ChildView init")
}
var body: some View {
VStack {
Text("param value: (value)")
Text("@ObservedObject bar: (vm.value)")
Button("(child) bar.value++") {
self.vm.value += 1
}
}
.onReceive(vm.$value) { value = $0 }
}
}
struct ContentView: View {
@State var value = 0
var body: some View {
VStack {
Text("(parent) (self.value)")
ChildView(value: $value)
}
}
}
但当我在ContentView中删除Text("(parent) (self.value)")
时,这似乎是正常的。
之所以会发生这种情况,是因为每当ChildView
被init
实例化时(当ContentView
的主体被重新计算时(,它都会创建一个值为0
的ViewModel
的新实例。
首先确定谁";拥有";数据。如果它是某个外部对象,如ViewModel
,那么它应该在某个实例寿命更长的地方进行实例化,例如在ContentView
中(但这将取决于您的真实用例(:
struct ContentView: View {
@State var value = 0
var childVm = ViewModel(v: 0)
var body: some View {
VStack {
Text("(parent) (self.value)")
ChildView(vm: childVm, value: $value)
}
}
}
struct ChildView: View {
@Binding var value: Int
@ObservedObject var vm: ViewModel
init(vm: ViewModel, value: Binding<Int>) {
self._value = value
self.vm = vm
print("ChildView init")
}
// ...
}
通常,所描述的行为是意料之中的,因为value
的真相来源在父级中,通过绑定更新它可以更新所有使用它的地方。这将导致重建父实体,因此重新创建子视图。
SwiftUI 2.0
解决方案是简单使用状态对象
struct ChildView: View {
@Binding var value: Int
@StateObject var vm = ViewModel(v: 0) // << here !!
// ... other code
SwiftUI 1.0+
使用更新的绑定值初始化视图模型
struct ChildView: View {
@Binding var value: Int
@ObservedObject var vm: ViewModel // << declare !!
init(value: Binding<Int>) {
self._value = value
self.vm = ViewModel(v: value.wrappedValue) // << initialize !!
// .. other code