P. *_*Ent 14 navigationview swiftui observableobject
我在视图中创建了一个 ObservableObject。
@ObservedObject var selectionModel = FilterSelectionModel()
Run Code Online (Sandbox Code Playgroud)
我在FilterSelectionModel'sinit函数中放置了一个断点,并多次调用它。因为这个 View 是 a 的一部分NavigationLink,所以我知道它是在那时创建的,并且与它一起创建, selectionModel 。当我导航到视图时,将再次创建 selectionModel。
在同一个视图中,我有一个“子视图”,我将 selectionModel 作为一个传递给子视图,EnvironmentObject以便子视图可以更改它。
AddFilterScreen().environmentObject(self.selectionModel)
Run Code Online (Sandbox Code Playgroud)
当子视图被关闭时,selectionModel 将再次创建并且对它所做的更改也消失了。
有趣的提示:在最顶层是一个NavigationView. 如果我添加
.navigationViewStyle(StackNavigationViewStyle())
Run Code Online (Sandbox Code Playgroud)
对此NavigationView,我的 selectionModel 的变化消失了。但是,如果我不添加navigationStyle,则子视图中的 selectionModel 更改仍然存在!!(但我不想要拆分导航视图,我想要堆叠的导航视图)
在这两种情况下 - 有或没有navigationStyle, selectionModel 都会被创建多次。我无法理解这些应该如何可靠地工作。
moh*_*wal 16
最新的 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)")
}
}
Run Code Online (Sandbox Code Playgroud)
在上面的示例中,只有负责创建该对象的视图 ( ContentViewUser ) 正在使用 注释该对象,而共享该对象的@StateObject所有其他视图 ( NameCount@ObservedObject ) 正在使用。
通过这种方法,每当您的父视图(ContentView)重新创建时,该User对象都不会被重新创建,并且它将保留其@State,而您的子视图仅observing针对同一个User对象,而不必关心其重新创建创建。
您可以在 init 方法中实例化 observable 对象,这样您就可以保持其值,否则该值不会消失。
在视图文件中以这种方式实例化。
@ObservedObject var selectionModel : FilterSelectionModel
init() {
selectionModel = FilterSelectionModel(value : "value to be saved from disappearing")
}
Run Code Online (Sandbox Code Playgroud)
在 viewModel 文件中以这种方式实例化。
class FilterSelectionModel : ObservableObject {
@Published var value : String
init(value : String) {
self.value = value
}
}
Run Code Online (Sandbox Code Playgroud)
这是我找到的一种解决方法,但仍然多次调用 init 方法,并且我没有在此问题上取得任何成功。
为了在导航视图中声明视图时停止多次初始化 ViewModel,并且 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()
}
}
Run Code Online (Sandbox Code Playgroud)
你可以这样称呼它...
NavigationLink(destination: LazyView { ViewTobePresented() })
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2495 次 |
| 最近记录: |