SwiftUI : NavigationStack in new iOS 18 TabView pushes twice when path in parameter

Hello,

With iOS 18, when NavigationStack is in new TabView, with path parameter containing current navigation state is set, the navigation destination view is pushed twice.

See below with example that pushes twice on iOS 18 but is correct on iOS 17

@MainActor
class NavigationModel: ObservableObject {
    static let shared = NavigationModel()
    
    @Published var selectedTab: String
    @Published var homePath: [Route]
    @Published var testPath: [Route]
}


struct ContentView: View {
    @StateObject private var navigationModel: NavigationModel = NavigationModel.shared
    
    var body: some View {
        TabView(selection: $navigationModel.selectedTab){
            HomeView()
                .tabItem {
                    Label("Home", systemImage: "house")
                }
                .tag("home")
            
            TestView()
                .tabItem {
                    Label("Test", systemImage: "circle")
                }
                .tag("test")
        }
    }
}


struct HomeView: View {
    @StateObject private var navigationModel: NavigationModel = NavigationModel.shared

    var body: some View {
        NavigationStack(path: $navigationModel.homePath){
            VStack{
                Text("home")
                NavigationLink(value: Route.test1("test1")){
                    Text("Go to test1")
                }
            }
            .navigationDestination(for: Route.self){ route in
                NavigationModelBuilder.findFinalDestination(route:route)
            }
        }
    }
}

I don't what causes the issue because it works well on iOS 16 and iOS 17. I think the path is somehow reset but I don't why (maybe by the TabView ?)

Note that the bug only occurs with TabView. Don't really know if it is a TabView bug or if it is on my side.

I filed a feedback with sample project FB14312064

Answered by brebispanique in 799115022

The issue seems to be fixed in iOS 18 beta 5

@ulian_onua I spoke too soon, and the issue does still occur, just much less frequently than before. While most of the time I no longer see the double-push of views, in some situations the exact same code will do a double-push. I don't know what makes those situations different than the situations where it doesn't happen.

So, in short, the issue is NOT fixed in iOS 18.1 beta 2

@sjb_s thank you for your feedback.

You can see my code in the post above that contains the code that always fails (double-push always happens) and some explanation.

Also I created the Bug report with the full descriptions and steps how to reproduce this bug: https://feedbackassistant.apple.com/feedback/14743917

@DTS Engineer we really your help here please.

I was using a NavigationPath (this is in my real app, not in my test code), and found that removing that fixed all my issues. My use is pretty simple and I don't need to use a path with the NavigationStack

The issue IS NOT fixed in Xcode 16 Beta 6 + iOS 18 Beta 7.

This issue still persists in the latest 18.0 beta.

I am experiencing this issue, although only when NavigationLinks at tapped after a list has been filtered using .searchable. That is, rows containing a NavigationLink that normally will only lead to one push on the stack will modify the path twice when that row is tapped after filtering the list with a search term using a .searchable search box.

This remains present in both iOS 18 beta 7 and in iOS 18.1 beta 2.

Still present in iOS 18 beta 8.

In my case, a successful workaround has been moving my convenience modifier around navigationDestination to be used directly within the NavigationStack.

Broken example:

NavigationStack(path: $navModel.myFarmTabPath) {
                MyRootScreen()
                    .appNavigationDestinations() // <- My wrapper around destination selection
            }

Working example:

NavigationStack(path: $navModel.myFarmTabPath) {
                MyRootScreen()
                    .navigationDestination(for: Screen.self) { screen in
                       return screen.representedDestination
                    }
            }

To keep things tidy and allow for easier re-use in my tab views, I've added an extension to Screen which returns a destination:


extension Screen {
    @ViewBuilder
    var representedDestination: some View {
        switch self {
        case .screenOne:
            ScreenOne()
        case .screenTwo:
            ScreenTwo()
        }
    }

I still had the issue in iOS 18 beta 8. In case someone is using several navigationDestinations on a view. In my case it helped to change the order of these. Not sure why but it worked.

I am using only one navigationDestination, but it helped to move the modifier to another view. thanks NickYaw.

It seems that this issue still hasn’t been resolved in the official release of iOS 18. As mentioned in the original post, it appears to be related to a problem with TabView and NavigationStack. While using a Path-based solution does fix the issue, there are some instability concerns, such as multiple screens being popped when using the back gesture. Most importantly, I prefer using the NavigationLink(value:...) format, so I hope this issue is addressed soon.

This makes my app unusable on the iOS 18 SDK, so I need to stay with Xcode 15 for now. No amount of removing the path from the NavigationStack, or using NavigationPath, helped.

Hi everyone,

I'm also experiencing the double-push issue with NavigationLink in iOS 18, especially when used within a TabView. This bug has been incredibly frustrating, as it disrupts the user experience significantly.

As a workaround, I've reverted to using the old-style NavigationLink with a destination and label, which thankfully seems to avoid the issue, but it's far from an ideal solution.

Is there any update or a way to track the status of this bug? It would be great to know if Apple is working on a fix.

Thanks, Ruben

I found that using the new Tab API (https://developer.apple.com/documentation/swiftui/tab) on iOS 18 resolves the problem for me.

The issue isn't fixed and still can be represented on iOS 18.0

The solution of @kh_bb helps for the most of cases but the issue can be representated in some specific cases.

@cutecutealien it didn't help me, unfortunately. Can you please send you example?

SwiftUI : NavigationStack in new iOS 18 TabView pushes twice when path in parameter
 
 
Q