16

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

@ObservedObject var selectionModel = FilterSelectionModel()

FilterSelectionModel我在's函数中放置了一个断点init,它被多次调用。因为这个 View 是 a 的一部分NavigationLink,所以我知道它是在随后创建的,并且与它一起创建了 selectionModel。当我导航到视图时,将再次创建 selectionModel。

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

AddFilterScreen().environmentObject(self.selectionModel)

当子视图被关闭时,selectionModel 再次被创建,对它所做的更改也消失了。

有趣的注意事项:在最顶层是一个NavigationView. 如果我添加

.navigationViewStyle(StackNavigationViewStyle())

对此NavigationView,我的 selectionModel 的更改消失了。但是,如果我添加navigationStyle,则在子视图中所做的 selectionModel 更改仍然存在!(但我不想要拆分导航视图,我想要堆叠导航视图)

在这两种情况下 - 无论有没有navigationStyle, selectionModel 都会被创建多次。我无法理解这些应该如何可靠地工作。

4

2 回答 2

8

你可以在 init 方法中实例化 observable 对象,这样你就可以保持它的值或者值不会消失。

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

@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 方法,但我没有在这个问题上取得任何成功。

为了停止 ViewModel 的多次初始化,因为在 Navigation View 中声明了视图,并且 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() }) 
于 2020-03-24T07:36:36.010 回答
7

最新的 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)")
  }
}

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

通过这种方法,每当您的父视图(ContentView)被重新创建时,该User对象将不会被重新创建并且它将保持其@State,而您的子视图只是observing针对同一个User对象而不必关心它的重新创建。

于 2021-03-07T18:48:12.823 回答