SwiftUI @State 变量没有被取消初始化

Posted

技术标签:

【中文标题】SwiftUI @State 变量没有被取消初始化【英文标题】:SwiftUI @State variables not getting deinitialized 【发布时间】:2019-12-19 09:40:16 【问题描述】:

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

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

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

【问题讨论】:

作为一种解决方法,您可以使用视图的onAppear 方法重新评估状态。我必须强调,这确实是一种解决方法,并且可能有更好的方法。 我们不知道,至少我不知道,SwiftUI 如何管理其特殊的State(或ObservedObject)对象,我们可以'关于变量的反初始化过程不多说了。但就Apple 指导我们如何控制数据源的数据流 而言,可以推断您拥有数据的单一访问点。话虽这么说,你可以试试the approach discussed here @EvZ 我也来到了那个解决方案,但不幸的是,当我在 onAppear 中设置值时,应用程序会根据该值崩溃 bc 我在 List 中添加一个部分,xcode 抱怨说只警告一次:UITableView 被告知在视图层次结构中布局其可见单元格和其他内容... 【参考方案1】:

在这种情况下,@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 示例

【讨论】:

以上是关于SwiftUI @State 变量没有被取消初始化的主要内容,如果未能解决你的问题,请参考以下文章

如何在 SwiftUI 中延迟 @State 变量的设置值

一旦新的 SwiftUI 视图完全加载,@State 变量就会被清除

SwiftUI,为啥部分视图没有刷新? @State 变量未更新

在 SwiftUI 中用另一个 @State 属性值初始化 @State 属性

SwiftUI - 如何创建全局 @State 变量?

SwiftUI-将@State变量传递给多个视图麻烦