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()
  }
}






Post not yet marked as solved Up vote post of JanC Down vote post of JanC
51k views
  • The WA works. But this is still present in 14.7.

Add a Comment

Replies

For the same app, I get this error running on a iOS 14.8 device but I do NOT get the error on a 15.3.1 device.

Maybe I found the reason of this bug... if you use iOS 15 (not found iOS 14), and you write the code NavigationLink to go to same View in different locations in your projects, then this bug appear. So I simply made another View that has different destination View name but the same contents... then it works.. you can try.... sorry for my poor English...

I had to set isDetailLink(false) to the NavigationLinks in order to stop this behaviour.

I was having this issue because i used

@State var date = Date() 

i removed it and the issue is no more there.

this solution did not work in my case : NavigationLink(...){ emptyView() }

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.