@State 和@ObservedObject 有什么区别,它们都可以用来持久化状态吗?

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

当我用谷歌搜索 "State vs ObservedObject" 时,第一个 result 来自 Hacking with Swift,它说的是 @ObservedObject:

This is very similar to @State except now we’re using an external reference type rather than a simple local property like a string or an integer.

我可以使用 @ObservedObject 创建持久状态吗?它是否像 @State 用于简单属性和 @ObservedObject 用于复杂对象 一样简单,还是有更多细微差别?

@ObservedObject 不持久状态

Can I use @ObservedObject to create persisted state?

就其本身而言,您不能。 Apple documentation@State 有这样的说法:

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

但是我发现 @ObservedObject 没有提到持久性,所以我构建了这个小演示来确认 @ObservedObject 不持久状态:

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()
    }
  }
}

每当您单击 value++ 按钮时,都会导致重新呈现 ChildView,因为 value 属性 已更改。 当视图因 属性 更改而重新呈现时,@ObservedObject 会重置

相比之下,如果您将 @State 变量添加到 ChildView,您会注意到它的值在 @ObservedObject 重置时不会重置。

使用持久状态 @ObservedObject

要使用 @ObservedObject 保持状态,请在父视图中使用 @State 实例化具体的 ObservableObject。所以要修复前面的例子,会像这样:

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()
    }
  }
}

class Bar 的定义与第一个代码示例没有变化。现在我们看到即使 value 属性 发生变化,该值也不会重置: