【问题标题】:SwiftUI @Binding value can not change and called initSwiftUI @Binding 值不能改变并调用 init
【发布时间】:2020-08-14 03:41:09
【问题描述】:

我想让一个选择器使用 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)") 时,它似乎是正常的。

【问题讨论】:

    标签: swift swiftui combine publisher


    【解决方案1】:

    通常,所描述的行为是预期的,因为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
    

    【讨论】:

      【解决方案2】:

      这是因为任何时候ChildView 得到init-ialized - 当ContentView 的主体被重新计算时会发生 - 它会创建一个新的ViewModel 实例,其值为0

      首先确定谁“拥有”数据。如果它是一些外部对象,比如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")
          }
          // ...
      }
      

      【讨论】:

        猜你喜欢
        • 2020-12-19
        • 1970-01-01
        • 2020-02-10
        • 2021-10-11
        • 1970-01-01
        • 2022-06-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多