Skip to content

SwiftUI navigation dismiss bug demo app: Rapidly calling removeLast on system/custom navigation path causes NavigationStack and navigation path states to become desynced.

boscojwho/NavigateDismissBug-SwiftUI

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

5 Commits
 
 
 
 

Repository files navigation

SwiftUI NavigationDismiss bug demo

Rapidly calling removeLast on system/custom navigation path causes NavigationStack and navigation path states to become desynced.

Overview:

Bug report filed on Sept. 19, 2023 (FB13189889)

This demo app shows how programmatically dismissing views on a NavigationStack by manipuating its navigationPath can cause the stack (UI state) and path (data state) to become "de-synced".

  1. When using the environment dismiss action, the navigationPath's last value is removed after the "pop" animation completes.
  2. When using programmatic dismissal (i.e. manually manipulating the navigationPath), the navigationPath's last value is removed before the "pop" animation begins.

The latter's behaviour causes the issues described below.

Steps to Reproduce:

(You can switch between SystemNavigationPathView and CustomNavigationPathView in ContentView)

  1. Add 10 or more detail views onto navigation stack using the on-screen button.
  2. Rapidly tap (more than 10 times) the "Navigate Back ((path.count))" overlay button so that navigationPath.count == 0.
  3. NavigationPath now reports count == 0, but NavigationStack still shows one or more detail views.
  4. At this point, performing any of the following steps results in unexpected behaviour
    1. Navigate back using a custom back button no longer works because navigationPath is already empty!
    2. Using the system back button causes stack to go back to an empty view with animation.
    3. Attempting to push a new detail view using on-screen button causes stack to perform a "pop" action instead (or some other unexpected action).

Expected Behaviour:

Either

  1. If user rapidly taps custom back button, say, 7 times, navigation stack should go back 7 pages.
  2. NavigationPath should ignore programmatic manipulation while animation is in-flight. There should be a way to coordinate programmatic manipulation of a navigation path with its associated animation. (Using withAnimation or withAnimation(…completion) on iOS 17 has no effect).

Workaround:

  • The custom back button (e.g. a persistent overlay or tab button not associated with any detail view) would have to gain access to each view's environment dismiss action, and use that to navigate back.
  • We'll likely use this workaround, but it's a lot more cumbersome than being able to just manipulate a navigationPath in a root view.
  • Link to PR that uses this workaround

Additional Notes:

  • This happens on iOS 16.5, 16.6 and iOS 17 (RC)
  • This can be reproduced on device and in simulator.

About

SwiftUI navigation dismiss bug demo app: Rapidly calling removeLast on system/custom navigation path causes NavigationStack and navigation path states to become desynced.

Topics

Resources

Stars

Watchers

Forks

Languages