14.5 beta3 NavigationLink unexpected pop

Yep. The view with the links gets recalculated and that causes the pop. Nothing that affects the NavigationLinks is getting touched though. It's the re-rendering itself that's triggering it, for sure.

Using vanilla SwiftUI in WatchOS 7.4 (the new release) and the problem exists there as well. Same workaround fixes it.

1 Like

Here's my extremely simple view—no state at all—which illustrates the problem. I would think I'm mis-using the API, but XCode is helpfullying saying, at run-time "Unable to present. Please file a bug." This began yesterday with Apple's release of XCode 12.5/etc. This uses the "split-screen" feature of NavigationView (supplying two views). Note that the problem does not exist when .navigationViewStyle(StackNavigationViewStyle()) is added (this changes the navigation in a way that I don't want, so is not a "solution"). Thanks for reviewing, all!

import SwiftUI

struct ContentView: View {
  var body: some View {
    NavigationView {
      Group {

        NavigationLink(destination: Text("Destination 1")) {
          Text("Hello, 1!")
        }
        NavigationLink(destination: Text("Destination 2")) {
          Text("Hello, 2!")
        }
        NavigationLink(destination: Text("Destination 3")) {
          Text("Hello, 3!")
        }
        
      }
      
      Group {
        Text("Secondary")
      }
    }

  }
}
1 Like

I’m running into this issue too and it also affects code compiled with the 14.4 SDK running on iPadOS 15.5.
The only workarounds I’ve found are embedding the NavigationLinks in a List or Form, though both apply a number of style and behaviour changes to their children which prevents me from using this approach in production.

Strangly the issue also seems to disappear if you have fewer than three NavigationLinks.

Interesting (for me at least) it seems the first time a link is triggered the destination view is presented correctly, but subsequent triggers fail.

Feel free to dupe my feedback/radar FB9091466, if you already have one let me know and I’ll reference it in mine.

I've also uploaded my sample project here: navvy/ContentView.swift at master · tomhut/navvy · GitHub

2 Likes

I can confirm this issue. My app was working perfectly fine before the recent update. Now navigation is completely broken, screens stay white or multiple screens overlay each other with a semi-transparent background.

I have a device which still runs iOS 14.4, but the problem also occurs on it. So I assume that XCode 12.5 has some changes which cause this issue and not iOS itself.

1 Like

I have exactly the same issue, started occurring with Xcode 12.5 / iOS 14.5. Only on iPadOS, not using StackNavigationViewStyle (I want two columns) and with 5 NavigationLinks in the same view.

Interesting (for me at least) it seems the first time a link is triggered the destination view is presented correctly, but subsequent triggers fail.

This happens for me as well. I hope this can be fixed relatively quickly.

1 Like

This may be related to this note from the developer release notes:

  • The destination of NavigationLink that only differs by local state now resets that state when switching between links as expected. (72117345)

Now, what that actually means I have no idea.

Make sure to report the issue to Apple using Feedback if you want any chance to see it fixed. (Feedback currently seems to be down.)

Seeing the same issue on a fairly small application, for me it was happening with a similar setup as OP.

Exactly two navigation links on a screen using two distinct elements of the state.

Temp fix by adding a hidden NavigationLink :\ - feedback submitted.

Hey folks, I was able to reliably reproduce the issue without using TCA aka vanilla SwiftUI (I've update my repo).
I narrowed it down to 2 main cases (so far):

  1. Updating an @State property only when that property is referenced anywhere in the view hierarchy.
  2. Updating an @ObservedObject / @StateObject property even when it is not referenced in the view hierarchy.

Ensuring the View does not have exactly 2 NavigationLinks works around the issue in both cases.

We are seeing this behavior quite frequently using TCA because of the design of composing states and its use of @ObservedObject for the ViewStore.

Has there been any fix to this?

My macOS app now keeps showing "Unable to present" when clicking on a NavigationLink and the child view never opens. The app is essentially unusable after the Big Sur 11.3 / Xcode 12.5 update.

Surely many others are impacted?

I tried the EmptyView() fix to no avail.

I also had exactly this problem.

Above gist is a simple code for my problem situation.

And the gist below is the code of the way I solved the problem right away.

I don't know why this issue happen. but still occurred in iOS 14.5, iOS 14.6

If you have better solution, please let me know.

I ran you code and there is no problem. Xcode Version 12.5 (12E262)

Your used of Groups doesn't make sense. The Text("Secondary") is not shown on screen. All should be just inside one VStack

@young Thanks for running my code sample. Are you running it in an iPad where both views of the NavigationView (primary and secondary) are in effect and displayed? If on the iPhone it works fine—the bug appears when the Secondary is displayed because, as I mentioned, "This uses the split-screen feature of NavigationView (supplying two views)." I agree a VStack is better but it's beside the point and changing to a VStack does not fix the problem. I just re-ran it in XCode 12.5 (12E262). If you try it in iPad, please let me know if the bug exhibits or not.

I was running in. iPhone. In iPad does show problem:

So it shows blank screen with "< Back" button on start up and NavLink only navigate once, after none work. Don't see "Unable to present. Please file a bug."

1 Like

Fixed in XCode 13 Beta / iPadOS 15 simulator! My code sample from April 28 (above: using NavigationLink in side-by-side 2-panel iPad view, with no state at all), which was broken in XCode 12 with iOS 14.5 now works well in XCode 13 Beta (running in the iPadOS 15 simulator). Good enough for me!

2 Likes

Thanks man I had the same issue with that on none beta version
it fixed my issue of unexpected pop on @EnvironmentObject value change.

i think the bug is still in it.
but with @EnvironmentObject

my screen transition was
Scanner to confirmation to login to home to login to scanner to confirmation to login to home and in home I tried to change @EnvironmentObject and it poped me to Scanner screen instead just new pop up

In case folks were looking for more concrete examples of how to fix the problem in TCA, a discussion was opened on GitHub recently: Multiple NavigationLink with composable architecture · Discussion #670 · pointfreeco/swift-composable-architecture · GitHub

1 Like

I too have found that the bounce-back behavior is gone in Xcode 13 Beta/iOS 15 simulator. Happy to have found that! But frustrating to have to wait.

One more note.. in Xcode 12.5.1, I've found the culprit to be .navigationViewStyle(StackNavigationViewStyle()

With this enabled on the Top Level NavigationView, the second level navigation works, but the third level bounces back.
With this disabled on the Top Level NavigationView, the second level navigation works once, then I tap into the third level which works, but when I go back to the second level, I cannot tap onto any other items -- I have to first go back to the first level navigation, and then back into the second level.

TLDR: The problem happens with just 2 navigations.
Adding a third navigation stops the issue.

In my case I had:

(1) A tab view with a root view that had 2 navigation starting points

(2) the first and second navigations have quite a lot of nested views

(3) adding .navigationViewStyle(StackNavigationViewStyle() fixed the issue only for root views that had only one starting point of navigation

(4) as soon as I had another navigation coming from the same view the problem reappeared (only for iOS 14.5 to 14.8)

(5) solely adding the

NavigationLink(destination: EmptyView()) {
    EmptyView()
}

didn't work for me

(6) On my project I have a coordinator that is responsible for creating the viewModels (that are published properties) and I have a ContainerView that will handle all the navigation. The navigation links are created based on the existence or not of a viewModel, so if a viewModel exists that view will be presented and when the view is dismissed the viewModel will be set to nil. (I'll add the code that does that at the end)

(7) for some weird reason, adding a third navigation to the view that is responsible for the navigation stopped my container view to be re-rendered and the view to stop being popped back.

Simply adding the NavigationLink to the container didn't work, but using the modifier I'm using and setting the destination to be the Empty NavigationLink did.

This is the code that is used for the navigation:

    func navigation<Item, Destination: View>(
        item: Binding<Item?>,
        @ViewBuilder destination: (Item) -> Destination
    ) -> some View {
        let isActive = Binding(
            get: { item.wrappedValue != nil },
            set: { value in
                if !value {
                    item.wrappedValue = nil
                }
            }
        )
        return navigation(isActive: isActive) {
            item.wrappedValue.map(destination)
        }
    }

    func navigation<Destination: View>(
        isActive: Binding<Bool>,
        @ViewBuilder destination: () -> Destination
    ) -> some View {
        overlay(
            NavigationLink(
                destination: isActive.wrappedValue ? destination() : nil,
                isActive: isActive,
                label: { EmptyView() }
            )
        )
    }

This is how my container view works. My coordinator has Published properties that are optional viewModels and the existence or not of that viewModel is what triggers the isActive value on the navigation link. Adding that last .navigation worked. My empty container just has the empty navigationLink