Hello, community and Apple engineers. I need your help.
Our app has the following issue: NavigationStack pushes a view twice if the NavigationStack is inside TabView and NavigationStack uses a navigation path of custom Hashable elements.
Our app works with issues in Xcode 18 Beta 13 + iOS 18.0. The same issue happened on previous beta versions of Xcode 18. The issue isn’t represented in iOS 17.x and everything worked well before iOS 18.0 beta releases.
I was able to represent the same issue in a clear project with two simple views. I will paste the code below.
Several notes:
- We use a centralised routing system in our app where all possible routes for navigation path are implemented in a View extension called
withAppRouter().
- We have a
enum RouterDestination
that contains all possible routes and is resolved inwithAppRouter()
extension. - We use
Router
class that contains@Published var path: [RouterDestination] = []
and this @Published property is bound to NavigationStack. In the real app, we need to have an access to this path property for programmatic navigation purposes. - Our app uses
@ObservableObject
/@StateObject
approach.
import SwiftUI
struct ContentView: View {
@StateObject private var router = Router()
var body: some View {
TabView {
NavigationStack(path: $router.path) {
NavigationLink(value: RouterDestination.next, label: {
Label("Next", systemImage: "plus.circle.fill")
})
.withAppRouter()
}
}
}
}
enum RouterDestination: Hashable {
case next
}
struct SecondView: View {
var body: some View {
Text("Screen 2")
}
}
class Router: ObservableObject {
@Published var path: [RouterDestination] = []
}
extension View {
func withAppRouter() -> some View {
navigationDestination(for: RouterDestination.self) { destination in
switch destination {
case .next:
return SecondView()
}
}
}
}
Below you can see the GIF with the issue:
What I tried to do:
- Use iOS 17+
@Observable
approach. It didn’t help. - Using
@State var path: [RouterDestination] = []
directly inside View seems to help. But it is not what we want as we need this property to be@Published
and located insideRouter
class where we can get an access to it, and use for programmatic navigation if needed.
I ask Apple engineers to help with that, please, and if it is a bug of iOS 18 beta, then please fix it in the next versions of iOS 18.0