When using one of the NavigationLink
initializers available to programatically push a view into the NavigationView
, the Back button malfunctions every other time. The first time it is tapped, the view pops and pushes again immediately. The second time around, it works fine (only pops). The third time the problem starts all over again.
The affected initializers are:
NavigationLink(destination: MyView(), isActive: $active) { ... }
NavigationLink(destination: MyView(), tag: 1, selection: $selection) { ... }
If we pop the view programatically, it all works fine.
Bug Report: FB6869419
Workaround: Yes, see below.
Fixed On: iOS 13.1
Stackoverflow Question: https://stackoverflow.com/questions/57273717/swiftui-navigationdestinationlink-deprecated
Code Sample (to reproduce)
window.rootViewController = UIHostingController(rootView: ContentView().environmentObject(Model()))
class Model: ObservableObject {
@Published var pushed = false
}
struct ContentView: View {
@EnvironmentObject var model: Model
var body: some View {
NavigationView {
VStack {
Button("Push") {
self.model.pushed = true
}
NavigationLink(destination: DetailView(), isActive: $model.pushed) { EmptyView() }
}
}
}
}
struct DetailView: View {
@EnvironmentObject var model: Model
var body: some View {
Button("Bring me Back") {
self.model.pushed = false
}
}
}
Workaround
Removing the default back button and adding our own will let us get through, until the bug gets fixed by Apple.
class Model: ObservableObject {
@Published var pushed = false
}
struct ContentView: View {
@EnvironmentObject var model: Model
var body: some View {
NavigationView {
VStack {
Button("Push") {
self.model.pushed = true
}
NavigationLink(destination: DetailView(), isActive: $model.pushed) { EmptyView() }
}
}
}
}
struct DetailView: View {
@EnvironmentObject var model: Model
var body: some View {
Button("Bring me Back") {
self.model.pushed = false
}
.navigationBarBackButtonHidden(true)
.navigationBarItems(leading: MyBackButton(label: "Back!") {
self.model.pushed = false
})
}
}
struct MyBackButton: View {
let label: String
let closure: () -> ()
var body: some View {
Button(action: { self.closure() }) {
HStack {
Image(systemName: "chevron.left")
Text(label)
}
}
}
}
Great catch.
Just submitted a bug report involving this issue as well. FB7462374
Omg, thought I was doing something wrong for hours.
Hi guys and thank you, Javier for spotting that bug!
It seems that it’s back again on 13.3, on 13.1 “standard back button” works prefect.
Does anybody know other workarounds in this case? Switching “back button” to “custom back button” works for me only in case of two screens connected. If I push one more view on the top of the navigation stack, @State flag isPresented switches back to false, and “custom back button” stops working. Would appreciate any ideas.
Andrey my recommendation is use https://github.com/biobeats/swiftui-navigation-stack or at least read over it and see if that helps you (though I’m over a month after your post and you’ve probably figured out a fix by now) — apparently using @State with navigation is just overall a bad idea (though interestingly enough, I’m seeing the same behavior you describe even when using ObservableObject and @Published in an “env” state class)
Yes navigationlink is very buggy. Example If I have multiple NavigationLinks deep into navigation hierarchy. Then I use presentationMode.wrappedValue.dismiss(), and on dismiss I am also passing ID to navigate to other screen from intermediate screen B (A -> B -> C/D, here back from D to B and based on id to C) then navigation link jumps all the stack to the root A with jumping screens. I need to add delay of 1 second when setting in B screen ID value to prevent this
I’m hoping for the next SwiftUI iteration to bring some big improvements in this area.
Thank you for this workaround!
There is another bug where the back button completely disappears.
using this works only once. After which the backbutton disappears.
however, using this (with exact same code) works all the time
iOS 14.2 / Xcode 12
Experiencing exactly same bug. Works every other time. Also changing binding value for isActive from DetailsScreen does nothing, but after that pressing back just pops screen.
So stupid…
this bug is still there and now, the programatic back button does not fix it at all.
It’s so frustrating to struggle with what should be an improving language and platform. I don’t know when I’m at fault or Apple is. Has this one been fixed? I’m running into a number of weird things and some are centred around Navigation, so I’m either paranoid or on to something.