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 aUITabBarController
>- each tab is a
UINavigationController
rootViewController
of nav controller is aUIHostingController
>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 NavigationLink
s. 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.