SwiftUI @State变量未初始化

时间:2019-12-19 09:40:16

标签: ios swift xcode swiftui combine

我有一个SwiftUI视图,其中声明了这样的条件

@State var condition = UserDefaults.standard.bool(forKey: "JustKey")

当我第一次将此视图推入导航堆栈时,条件变量正在获取正确的值。然后,当我弹出该视图时,我更改了UserDefaults中的值,但是当我再次按下此屏幕时,条件变量会记住它第一次获得的旧值。 因为每次我要在声明它的位置进入自定义视图时都想重新初始化条件变量,如何找到解决方法?

1 个答案:

答案 0 :(得分:2)

在这种情况下,@State的行为与预期的完全相同:作为其所附加组件的持久存储。

从根本上讲,使用NavigationLink推送视图就像视图层次结构中的任何其他组件一样。屏幕是否实际可见是实现细节。尽管SwiftUI在关闭屏幕后并没有真正呈现您的隐藏UI元素,但它确实会抓住View树。

您可以使用.id(_:)修饰符强制将视图完全抛弃,例如:

struct ContentView: View {
  @State var i = 0

  var body: some View {
    NavigationView {
      VStack {
        NavigationLink(destination: DetailView().id(i)) {
          Text("Show Detail View")
        }
        Button("Toggle") {
          self.i += 1
          UserDefaults.standard.set(
            !UserDefaults.standard.bool(forKey: "JustKey"),
            forKey: "JustKey")
        }
      }
    }
  }
}

切换按钮既可以修改 JustKey 的值,又可以增加我们传递给.id(i)的值。当id(_:)的单个参数更改时, id 修饰符告诉SwiftUI 这是一个不同的视图,因此,在SwiftUI运行时,它的差异算法会丢弃旧的一个并创建一个新的(带有新的@State变量)。详细了解 id here


以上说明提供了一种解决方法,但IMO不是一个好的解决方案。更好的解决方案是使用ObservableObject。看起来像这样:

@ObservedObject condition = KeyPathObserver(\.JustKey, on: UserDefaults.standard)

您可以在this SO answer处找到实现KeyPathObserver的代码和完整的Playground示例。