0

I'm having trouble with having EnvironmentObject and hidden NavigationLink.

The code is below. It just aims to navigate users from the ContentView to the SecondView and then to the ThirdView using simple NavigationLink while having hidden NavigationLink in ContentView. (CatView and DogView are just simple Views holding a Text)

The thing is when the app updates one of the EnvrionmentObject (which is not used for hidden NavigationLink) on the ThridView, it navigates me back to the SecondView.

class FlagEnv: ObservableObject {
    @Published var flag = false

    func toggleFlag() {
        flag.toggle()
    }
}

class SelectionEnv: ObservableObject {
    @Published var selected: Selection?

    enum Selection: String {
        case cat, dog
    }
}

struct ContentView: View {
    @StateObject private var flag = FlagEnv()
    @StateObject private var selection = SelectionEnv()

    var body: some View {
        let _ = Self._printChanges()
        NavigationView {
            VStack {
                // Hidden NavigationLinks supposed to be triggered by selection
                NavigationLink(tag: .cat, selection: $selection.selected, destination: CatView.init) { EmptyView() }
                NavigationLink(tag: .dog, selection: $selection.selected, destination: DogView.init) { EmptyView() }

                NavigationLink("Go to 2nd view") {
                    SecondView()
                }
            }
        }
        .environmentObject(flag)
        .environmentObject(selection)
    }
}

struct SecondView: View {
    var body: some View {
        let _ = Self._printChanges()
        NavigationLink("Go to 3rd view") {
            ThirdView()
        }
    }
}

struct ThirdView: View {
    @EnvironmentObject var flag: FlagEnv

    var body: some View {
        let _ = Self._printChanges()
        Button("Toggle Env Flag") {
            flag.toggleFlag()
        }
    }
}

For your reference, _printChanges() prints the logs in the console as below.

// When app launched
ContentView: @self, @identity, _flag, _selection changed.

// When navigated to Second view
SecondView: @self changed.

// When navigated to Third view
ThirdView: @self, @identity, _flag changed.

// When toggle the flag
ThirdView: _flag changed.
ContentView: _flag changed.
SecondView: @self changed.

However, if I add .isDetailLink(false) to the NavigationLink in the ContentView as below, it doesn't happen but not sure why.

NavigationLink("Go to 2nd view") {
  SecondView()
}
.isDetailLink(false)

Do you know why the original issue happen and how can I solve it, and also why the isDetailLink changes the behavior?

Toru
  • 517
  • 1
  • 5
  • 19
  • 1
    You change state object it refreshes body, so rebuild navigation view which destroys previous navigation stack... with `.isDetailLink(false)` stack is flat (only one destination in it, latest replaces previous), so ... something like that. Actually it is long-known behavior (one of corresponding posts https://stackoverflow.com/a/59546127/12299030). And NavigationView has deprecated, so start looking onto NavigationStack – Asperi Jun 28 '22 at 10:06
  • @Asperi Thanks! First of all, NavigationStack can't be an option for me because my app supports iOS 14 and above. And regarding your suggestion in the other post, I tried exactly your code and it stops working if I add the follwoing code to the ContentView. `NavigationLink(tag: 0, selection: $object.selection, destination: EmptyView.init) { EmptyView() }` – Toru Jun 28 '22 at 23:50

0 Answers0