I have the code below where I use a NavigationLink to add multiple child views on button click. However, as soon as I increase the EnvironmentObject value, all views reset, and only ChildView 1 remains.
@main
struct NavigationResetIssueApp: App {
var body: some Scene {
WindowGroup {
ContentView()
.environmentObject(Observer())
}
}
}
enum Route {
case child
}
class Observer: ObservableObject {
@Published var observedValue: Int = 0
init() {
print("Observer init")
}
}
struct ContentView: View {
@EnvironmentObject var observer: Observer
@State var navigateToRoute: Route?
var body: some View {
NavigationView {
VStack {
Text("Current observer Value: (observer.observedValue)")
.font(.headline)
.padding()
Button("Move to Child View") {
navigateToRoute = .child
}
.padding()
NavigationLink(destination: ChildView(num: 1) ,
tag: Route.child,
selection: $navigateToRoute,
label: { })
}
}
}
}
struct ChildView: View {
@EnvironmentObject var observer: Observer
@State var viewNum:Int
@State var navigateToRoute: Route?
init(num:Int) {
self.viewNum = num
print("initializing ChildView")
}
var body: some View {
VStack {
let _ = print("chilChildViewd body")
Text("observer Value: (observer.observedValue)")
.font(.headline)
.padding()
Button("Incrtease Observer Value") {
observer.observedValue += 1
}
.padding()
Button("Move to Next Child View") {
navigateToRoute = .child
}
.padding()
NavigationLink(destination: ChildView(num: self.viewNum+1) ,
tag: Route.child,
selection: $navigateToRoute,
label: { })
}
.navigationTitle("ChildView # (viewNum)")
}
}
In another place, I removed the use of EnvironmentObject in the ChildView controller and changed the EnvironmentObject value after 5 seconds in the content view. Again, all child views reset, and only the first child view remains. Here is the updated code:
struct ContentView: View {
@EnvironmentObject var observer: Observer
@State var navigateToRoute: Route?
var body: some View {
NavigationView {
VStack {
Text("Current observer Value: (observer.observedValue)")
.font(.headline)
.padding()
Button("Move to Child View") {
navigateToRoute = .child
}
.padding()
NavigationLink(destination: ChildView(num: 1) ,
tag: Route.child,
selection: $navigateToRoute,
label: { })
}
}.onAppear(perform: {
DispatchQueue.main.asyncAfter(deadline: .now() + 10, execute: {
print("------- ContentView After 5 sec -------")
observer.observedValue = 50
})
})
}
}
struct ChildView: View {
@State var viewNum:Int
@State var navigateToRoute: Route?
init(num:Int) {
self.viewNum = num
print("initializing ChildView")
}
var body: some View {
VStack {
let _ = print("chilChildViewd body")
Button("Move to Next Child View") {
navigateToRoute = .child
}
.padding()
NavigationLink(destination: ChildView(num: self.viewNum+1) ,
tag: Route.child,
selection: $navigateToRoute,
label: { })
}
.navigationTitle("ChildView # (viewNum)")
}
}
Kindly let me know how to prevent this behavior.
Thank you so much for your attention and participation.
2
Answers
Try this approach using
@StateObject private var observer = Observer()
to letthe View/App observe and manage the model. Note also,
NavigationView
is deprecated useNavigationStack
instead.
Have a look at this Apple link Monitoring data it gives you some good examples of how to manage data in your app.
In addition to moving the Observer out to a
@State
var I think you got the navigation all mixed up. Try theNavigationStack
it is far more simple.e.g.: