SwiftUI NavigationLink pops out by itself

I have a simple use case where a screen pushes another screen using the NavigationLink. There is a strange behaviour iOS 14.5 beta where the pushed screen is popped just after being pushed.

I manage to create a sample app where I reproduce it. I believe the cause is the presence of @Environment(\.presentationMode) that seem to re-create the view and it causes the pushed view to be popped.


The exact same code works fine in Xcode 12 / iOS 14.4



Here is a sample code.

Code Block swift
import SwiftUI
public struct FirstScreen: View {
  public init() {}
  public var body: some View {
    NavigationView {
      List {
        row
        row
        row
      }
    }
  }
  private var row: some View {
    NavigationLink(destination: SecondScreen()) {
      Text("Row")
    }
  }
}
struct SecondScreen: View {
  @Environment(\.presentationMode) var presentationMode: Binding<PresentationMode>
  public var body: some View {
    VStack(spacing: 10) {
      NavigationLink(destination: thirdScreenA) {
        Text("Link to Third Screen A")
      }
      NavigationLink(destination: thirdScreenB) {
        Text("Link to Third Screen B")
      }
      Button("Go back", action: { presentationMode.wrappedValue.dismiss() })
    }
  }
  var thirdScreenA: some View {
    Text("thirdScreenA")
  }
  var thirdScreenB: some View {
    Text("thirdScreenB")
  }
}
struct FirstScreen_Previews: PreviewProvider {
  static var previews: some View {
    FirstScreen()
  }
}






I'm seeing this on watchOS. Unfortunately, isDetailLink is not available.

Using a NavigationLink inside a TabView is what triggers this behavior for me. Able to reproduce it with the following view:

struct ContentView: View {

    var body: some View {

        TabView() {

            NavigationLink("Test", destination: EmptyView())

        }

    }

}

I see the following warning when I do not set the TabView's selection:

TestNav WatchKit Extension[15697:678189] [SwiftUI] Accessing State's value outside of being installed on a View. This will result in a constant Binding of the initial value and will not update.

I can set selection to a constant and the warning goes away, but the behavior persists.

TabView(selection: .constant(0)) { ... }

For me the problem was the way I made the custom tabBar. It wasn't working well so I deleted it and remade it in a different way and simpler way. The problem is gone. I would suggest before you look for a workaround try to fix your navigationViews.

For me it was a LazyVStack higher up in the calling tree.

As explained in these documents, using navigationStack with following NavigationLink usage is solved problem for me.

https://developer.apple.com/documentation/swiftui/navigationlink

https://developer.apple.com/documentation/swiftui/migrating-to-new-navigation-types

NavigationLink { FolderDetail(id: workFolder.id) } label: { Label("Work Folder", systemImage: "folder") }

Xcode 15 Beta 4 /. IOS 17 also has same issue but no work around yet.

SwiftUI NavigationLink pops out by itself
 
 
Q