SwiftUI NavigationView popping when observed object changes

583 Views Asked by At

There are three views. Main view, a List view (displaying a list of locations) and a Content view (displaying a single location). Both the List view and the Content view are watching for changes from LocationManager(GPS position).

If the user NavigateLinks to Content view from the List view and then the observed LocationManager changes then ContentView is popped off and the List view is displayed.

I have NavigationViewStyle set to .stack (which some found to help) but it had no effect.

Does anyone know what I am doing wrong?

// Main view

@StateObject var locations = Locations()
    var body: some Scene {
        WindowGroup {
            TabView(){
                NavigationView {
                    ListView()
                }.navigationViewStyle(.stack).tabItem {
                    Text("List")
                }
            }.environmentObject(locations)
        }
    }

// List view

@EnvironmentObject var locations: Locations
@ObservedObject private var locationManager = LocationManager()

  var body: some View {
            List(){
                ForEach(locations, id: \.id) {
                    loc in
                        NavigationLink(destination: ContentView(location: loc, locationManager: locationManager)) {
                            Text(loc.name)
                        }.isDetailLink(false)
                }
            }.listStyle(PlainListStyle())
        }.navigationTitle("List")

// Content/Detail view

   let location: Location
   let locationManager: LocationManager

   var body: some View { Text("I am detail") }
2

There are 2 best solutions below

1
On BEST ANSWER

What I ended up doing was having two observable objects, one for the List and one for Detail.

The observable objects are GPS coordinates so that when the Content view is displayed (you can keep a track of that by adding a state in onAppear for the View) you don't allow changes to the observable object for the List.

In other words the observable object that the List view had, didn't change if the Content view was visible. I did this in code by simply ignoring any location updates in that object if the current view was Content/Detail.

This worked perfectly.

So instead of this:

enter image description here

I did this

enter image description here

3
On

It pops because your objects are not unique. Think about this:

You are inside a view called Alen now you refresh that view and it's called Alenx, SwiftUI pops you back because the data is different.

The way to make it stay is to make the elements unique (Identifiable), for this you can assign some unique id to your models, here's 1 way of doing it:

struct Example: Identifiable {
    
    let id = UUID()
    
    var someValue: String
    
    private enum CodingKeys: String, CodingKey { case someValue }
}