pointfreeco/swift-navigation

Setting `destination` to nil shows empty screen with "Back"-button, works only once

Closed this issue · 2 comments

In my little app, I am trying to show an edit screen. The model of the screen that hosts to button to drill down to that view has a destination property. When I navigate to the edit screen, I hide the "Back'-button and show cancellation and confirmation buttons in the toolbar in their respective places.

.navigationDestination(
                    unwrapping: $model.destination,
                    case: /VocabularySetDetailViewModel.Destination.edit
                ) { $editModel in
                    VocabularyAddEditView(model: editModel)
                        .navigationBarBackButtonHidden(true)
                        .toolbar {
                            ToolbarItem(placement: .confirmationAction) {
                                Button {
                                    model.destination = nil
                                } label: {
                                    Text("Confirm")
                                }
                            }
                            ToolbarItem(placement: .cancellationAction) {
                                Button {
                                    model.destination = nil
                                } label: {
                                    Text("Cancel")
                                }
                            }
                        }
                }

For now, I am just setting destination to nil in both cancellation and confirmation button, expecting to get back to the host screen.
What really happens though is that it gets back to an empty screen that just shows the "Back"-button. Tapping on it brings me back to the hosting screen.

When I now drill down to an item again that I want to edit, neither the cancellation nor the confirmation button work. I can see that destination is set to nil when tapping either button by observing it in didSet, but nothing actually happens in terms of navigation.

I know the above code is really only a small part of the app, but I hope that this might be a common/known thing that someone recognises... Anyways, you can see what's happening in below animated gif.

Xcode-Vocabulary — Vocabulary xcodeproj-20230314-180841

This is a bug in SwiftUI and something we discussed in episode 217 (at 23:39). If you simply nil out state driving a navigationDestination it will not pop the screen off the stack. Typically you can work around by adding @Environment(\.dismiss) to the child view, but that won't work directly for you since you are doing this directly in the navigationDestination content closure.

In order to make use of the hack workaround I think you need to wrap VocabularyAddEditView+toolbars in a little view so that you get access to @Environment(\.dismiss) for just that child view, and then invoke dismiss() when you write nil to the state.

Also I don't think this is an issue with the library, but rather an existing Apple bug. We've filed a bunch of Feedbacks for these bugs, and we encourage you to do the same.

So, I'm going to convert this to a discussion and we can continue the conversation over there.