What is the difference between @State and @ObservedObject, can they both be used to persist state?

前端 未结 1 2024
盖世英雄少女心
盖世英雄少女心 2021-01-03 08:39

When I Googled \"State vs ObservedObject\" the first result was from Hacking with Swift and it said about @ObservedObject:

This is very s

相关标签:
1条回答
  • 2021-01-03 08:45

    @ObservedObject does not persist state

    Can I use @ObservedObject to create persisted state?

    On its own, you cannot. The Apple documentation has this to say about @State:

    A persistent value of a given type, through which a view reads and monitors the value.

    But I found no mention of persistence with @ObservedObject so I constructed this little demo which confirms that @ObservedObject does not persist state:

    class Bar: ObservableObject {
      @Published var value: Int
    
      init(bar: Int) {
        self.value = bar
      }
    }
    
    struct ChildView: View {
      let value: Int
      @ObservedObject var bar: Bar = Bar(bar: 0)
    
      var body: some View {
        VStack(alignment: .trailing) {
          Text("param value: \(value)")
          Text("@ObservedObject bar: \(bar.value)")
          Button("(child) bar.value++") {
            self.bar.value += 1
          }
        }
      }
    }
    
    struct ContentView: View {
      @State var value = 0
    
      var body: some View {
        VStack {
          Spacer()
          Button("(parent) value++") {
            self.value += 1
          }
          ChildView(value: value)
          Spacer()
        }
      }
    }
    

    Whenever you click on the value++ button, it results in a re-render of ChildView because the value property changed. When a view is re-rendered as a result of a property change, it's @ObservedObjects are reset

    In contrast, if you add a @State variable to the ChildView you'll notice that it's value is not reset when the @ObservedObject is reset.

    Using persisted state with @ObservedObject

    To persist state with @ObservedObject, instantiate the concrete ObservableObject with @State in the parent view. So to fix the previous example, would go like this:

    struct ChildView: View {
      let value: Int
      @ObservedObject var bar: Bar  // <-- passed in by parent view
    
      var body: some View {
        VStack(alignment: .trailing) {
          Text("param value: \(value)")
          Text("@ObservedObject bar: \(bar.value)")
          Button("(child) bar.value++") {
            self.bar.value += 1
          }
        }
      }
    }
    
    struct ContentView: View {
      @State var value = 0
      @State var bar = Bar(bar: 0)  // <-- The ObservableObject
    
      var body: some View {
        VStack {
          Spacer()
          Button("(parent) value++") {
            self.value += 1
          }
          ChildView(value: value, bar: bar).id(1)
          Spacer()
        }
      }
    }
    

    The definition of the class Bar is unchanged from the first code example. And now we see that the value is not reset even when the value property changes:

    0 讨论(0)
提交回复
热议问题