Bug in NavigationStack's back button
Originator: | xiaogdgenuine | ||
Number: | rdar://FB9997893 | Date Originated: | Apr 28, 2023 |
Status: | Open | Resolved: | |
Product: | SwiftUI | Product Version: | SwiftUI 4 |
Classification: | Bug | Reproducible: | Yes |
It seems NavigationStack have state-inconsistent problem when dimissing a scrolling view. Steps to reproduce: 1. Create an empty SwiftUI project and paste codes below. 2. Run the app, then navigate 3 levels deep (By tapping any items in the list). 3. Scroll the current page view 4. Tap the "< Back" button while the view is still inertial scrolling. 5. Tap the "< Back" button again. 6. The app crashed with message "Fatal error: Can't remove more items from a collection than it contains". ```swift struct ContentView: View { @StateObject var holder = PathHolder() var body: some View { NavigationStack(path: holder.pathBinding) { PageView() .navigationDestination(for: Int.self) { _ in PageView() } } .environmentObject(holder) } } struct PageView: View { @EnvironmentObject var holder: PathHolder @Environment(\.dismiss) var dismiss var body: some View { VStack { if !holder.path.isEmpty { // Working version Button("dismiss") { holder.path.removeLast() } // Crash version // Button("dismiss") { // dismiss() // } } ScrollView { VStack { // Create 100 elements for scrolling ForEach(0 ..< 100) { _ in NavigationLink(value: 1, label: { Color.green .padding(.vertical) .overlay(Text("\(holder.path.count)").font(.title).foregroundColor(.red)) .frame(maxWidth: .infinity) .frame(height: 200) }) } } } } } } class PathHolder: ObservableObject { @Published var path: [Int] = [] { willSet { print("willSet", newValue, path) } didSet { print("didSet", oldValue, path) } } var pathBinding: Binding<[Int]> { Binding(get: { print("get \(self.path)") return self.path }, set: { print("set", $0) self.path = $0 }) } } ``` In the above example, if you tap on the "dismiss" button I provided instead of the default "< Back" button, the crash won't occur. Futher investigation shows that the "dismiss" method provided by NavigationStack is actually popping view first then modify the path binding value, so if you comment-out the "Crash version" and the app will crash again when tap on "dismiss" button.
Comments
Please note: Reports posted here will not necessarily be seen by Apple. All problems should be submitted at bugreport.apple.com before they are posted here. Please only post information for Radars that you have filed yourself, and please do not include Apple confidential information in your posts. Thank you!