SwiftUI-ObservableObject创建多次

时间:2019-12-30 15:48:24

标签: navigationview swiftui-bug observableobject

我已经在视图中创建了一个ObservableObject。

@ObservedObject var selectionModel = FilterSelectionModel()

我在FilterSelectionModel的{​​{1}}函数中放置了一个断点,它被多次调用。因为此View是init的一部分,所以我了解到它是在那时创建的,并且是selectionModel。当我导航到视图时,会再次创建selectionModel。

在同一视图中,我有一个“子视图”,在其中我将selectionModel传递为NavigationLink,以便子视图可以更改它。

EnvironmentObject

关闭子视图后,将再次创建selectionModel,并且对其所做的更改也将消失。

有趣的注释:最顶层是AddFilterScreen().environmentObject(self.selectionModel) 。如果我添加

NavigationView

对此.navigationViewStyle(StackNavigationViewStyle()) 而言,我的selectionModel的更改消失了。但是,如果我添加NavigationView,则在子视图中对selectionModel所做的更改仍然保留! (但是我不想要分割的导航视图,我想要一个堆叠的导航视图)

在两种情况下(无论是否带有navigationStyle,都会多次创建selectionModel。我无法确定应该如何可靠地工作。

2 个答案:

答案 0 :(得分:6)

您可以在init方法中实例化可观察对象,这样就可以保留其值,否则该值不会消失。

以这种方式在视图文件中实例化。

@ObservedObject var selectionModel : FilterSelectionModel

init() {
   selectionModel = FilterSelectionModel(value : "value to be saved from disappearing")
}

以这种方式在viewModel文件中实例化。

class FilterSelectionModel : ObservableObject {

  @Published var value : String

  init(value : String) {
     self.value = value
  }

}

这是我发现的解决方法,但仍然多次调用init方法,但在此问题上我没有获得任何成功。

为了在视图在导航视图中声明时停止ViewModels的多次初始化,并且SwiftUI使用值类型的struct,因此最终在视图出现之前对其进行了初始化,因此您可以将该视图转换为LazyView,因此只有在视图将要显示或显示时才对其进行初始化。

// Use this to delay instantiation when using `NavigationLink`, etc...
struct LazyView<Content: View>: View {
    var content: () -> Content
    var body: some View {
       self.content()
    }
}

您可以这样称呼...

 NavigationLink(destination: LazyView { ViewTobePresented() }) 

答案 1 :(得分:2)

最新的 SwiftUI 更新为这个问题带来了解决方案。 (iOS 14 以上)

@StateObject 是我们应该使用的而不是 @ObservedObject,但仅限于创建该对象的地方,而不是我们传递相同对象的子视图中的任何地方。

例如-

class User: ObservableObject {
    var name = "mohit"
}


struct ContentView: View {
  @StateObject var user = User()

  var body: some View {
    VStack {
      Text("name: \(user.name)")
      NameCount(user: self.user)
   }
  }
}


struct NameCount: View {
  @ObservedObject var user

  var body: some View {
    Text("count: \(user.name.count)")
  }
}

在上面的示例中,只有负责创建该对象的视图 (ContentView) 使用 User 和所有其他视图 (NameCount ) 共享对象正在使用 @StateObject

通过这种方法,无论何时重新创建父视图,都不会重新创建 @ObservedObject 对象,并且它会持续存在,而您的子视图仅 User 到相同的 observing对象不必关心它的重新创建。

希望这会有所帮助。快乐编码...