Navigation broken in iOS 18.4

All of a sudden, after iOS 18.4 was released, I am having tons of navigation problems in my app in production. Buttons navigating to empty pages, views seeming to 'freeze', top navigation bar mismatched with the content of the page. It seems that iOS 18.4 broke a critical piece of UIKit + SwiftUI bridging functionality that my project relies on.

** Originally posted in 'Core OS' topic but realized 'UI Frameworks > General' made more sense. My bad. **

My application is written with both UIKit and SwiftUI components. Here is a breakdown of my setup:

  • UIApplicationDelegate >
  • UIWindow >
  • rootViewController of window is a UITabBarController >
  • each tab is a UINavigationController
  • rootViewController of nav controller is a UIHostingController >
  • rootView of the hosting controller is a SwiftUI View

In my SwiftUI views, I have been using NavigationLink for horizontal 'push' style navigation in my SwiftUI views. I do not use NavigationView, I only rely on the bridging capabilities of UINavigationController to action on my NavigationLinks. This has never been an issue, until iOS 18.4 was released. Now, when running iOS 18.4, I am having all sorts of unexpected behavior in the UI. I will break down 2 of these use cases here:

Use case A:

In one of my SwiftUI views, I have a ForEach for which each element's view is a NavigationLink. This is using the NavigationLink(_ destination:,label:) initializer. Navigating forward from here works/looks normal.

However, once I try to navigate backward from that destination (tap the 'Back' button in top left), the view goes blank and the navigation bar at the top of the page (which is maintained by the UINavigationController instance) does not change. If I call popToRootViewController on that nav controller, the navigation bar at the top of the page returns to its normal state, but the view is still blank.

It is not until after I have called popToRootViewController, and then navigate to a different tab of the UITabBarController and return to the initial tab, does the SwiftuI content view (the one with the ForEach) finally redraw and the view hierarchy is restored.

Here is a warning that is logged in the console when I tap the 'Back ' button:

Top view controller's view unexpectedly not in window for navigation transition. Skipping layout. nav = <UINavigationController: 0x1110bbe00>, topVC = <TtGC7SwiftUI19UIHostingControllerV5MyApp10MyPage: 0x106814e00>

EDIT: If I replace the NavigationLink with a call to UINavigationController.pushViewController, I am still seeing the exact same behavior. Pressing back button makes the view empty > need to pop to root view controller and switch tabs in order to restore the view.

Use case B

Another instance of this issue happens whenever I try to use a NavigationLink inside of a view that itself was the destination of a NavigationLink in its parent view (i.e.: Root view > detail view > sub-detail view). For example, take the detail view destination in use case A. I have tapped a NavigationLink from the ForEach and landed on the detail view. Again, so far things work/look normal. Now, if I tap on another NavigationLink from that detail view, the view does not transition to the new page. The top navigation bar does transition, and shows the title and actions associated with this second destination. However, the view of this second destination is not displayed.

It is worth noting that the same warning I mentioned above is also logged when I tap the NavigationLink to navigate to this second destination.

Top view controller's view unexpectedly not in window for navigation transition. Skipping layout. nav = <UINavigationController: 0x109859400>, topVC = <TtGC7SwiftUI19UIHostingControllerVVS_19BridgedPresentation8RootView: 0x300ab8000>

Strangely, if I switch to a different tab of the UITabBarController and back to the initial tab, this second destination's view is successfully rendered. It seems that switching tabs in this UITabBarController is calling something in either SwiftUI or UIKit that is redrawing my views.

Conclusion

This is a serious issue with UIKit + SwiftUI bridging support. I have never had problems like this until devices started running iOS 18.4, and there is nothing in the iOS 18.4 changelog that suggests this was an intentional change. All of a sudden, after updating to the latest iOS version, my app is totally broken.

I want to be clear that I'm not using deprecated NavigationLink methods in these instances. My app's minimum deployment target is iOS 16.

I know that there are more modern navigation APIs like navigation stack, etc. I am looking for answers about my use case: whether it is officially unsupported as of iOS 18.4, whether this setup should be supported and this is indeed some sort of bug in iOS, or anything in-between. I'm happy to provide formatted code if needed for discussion purposes. This is about my entire app's view hierarchy so there are a lot of disparate lines of code that make up this problem.

Since iPadOS 18.4, I also discovered a broken NavigationSplitView. My app uses the NavigationSplitView, and I have the case that the view is a little going down. In iPadOS 18.3, it wasn’t. I also use a floating TabBar for the different views. So I have figured out that if I deactivate the TabBar, it works as before. It is very strange.

At moment it is only a design failure., but bothering.

Accepted Answer

This was due to my usage of UIActivityViewController in my SwiftUI views.

When relying on UINavigationController in a SwiftUI view, you can use the .toolbar modifier to add/manage navigation bar button items. I did this for my 'share' buttons, which would allow the user to share a link to my content via other apps on their phone. My solution mirrored the solution in this github repository, which is as follows:

  • Place a UIViewRepresentable in the background of your SwiftUI share button
    • Representing a custom, empty UIViewController
  • The custom UIViewController presents a UIActivityViewController when its var item: Binding<ActivityItem?> is given a value
    • give it a value when your button is tapped

Something about that view configuration totally broke the SwiftUI <-> UIKit bridging in iOS 18.4. Still not sure whether that was intentional, and since there is no deliberate messaging in the changelog I assume it was not intentional. If anyone else is having these problems, I hope this helps.

FWIW, I was planning to update my 'share' features to use ShareLink anyway, as I just recently increased the min deployment target to iOS 16, so this was a good reason to prioritize that work. That is what I would recommend to anyone else having this issue.

We are using uikit and on pro max devices we are facing this issue, pushing a viewcontroller from a rootviewcontroller, pretty much freezes in between transitioning of viewcontrollers. 18.4.1, such type of bugs which are not acknowledged are become exceedingly difficulty to convince customers, as apple insulates itself and we are stuck bearing the brunt.

Navigation broken in iOS 18.4
 
 
Q