Hello, This code has a NavigationSplitView,
whose sidebar is a List
and its detail contains a NavigationStack.
It is controlled by two @Observable
properties, a selection and a path. The path shown in the detail depends upon the selection in the List.
If I programmatically change the selection and path, the path will be set, but via SwiftUI backtraces (pasted below), it will clear out my path. This makes my code lose state. What am I doing wrong? Is this a bug? I'm using Xcode16 running against the iOS 18 simulator (although this also happens with iOS17).
To reproduce, Launch the App, Note that you are on the "first" selection. Tap "Nav Path: Path: second-100". You'll go to the "second" selection, but the path will be empty. If you place a breakpoint when the $path is cleared, you'll see it is being cleared by SwiftUI.
Backtrace when the path is emptied:
(lldb) bt
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 2.1
* frame #0: 0x00000001043295c0 DoubleNav.debug.dylib`Navigation.path.setter(newValue=0 values) at ContentView.swift:86:22
frame #1: 0x00000001043296d0 DoubleNav.debug.dylib`key path setter for Navigation.path : Navigation at <compiler-generated>:0
frame #2: 0x000000019485b500 libswiftCore.dylib`Swift.NonmutatingWritebackBuffer.__deallocating_deinit + 132
frame #3: 0x0000000194a351c4 libswiftCore.dylib`_swift_release_dealloc + 28
frame #4: 0x0000000194a35bd4 libswiftCore.dylib`bool swift::RefCounts<swift::RefCountBitsT<(swift::RefCountInlinedness)1>>::doDecrementSlow<(swift::PerformDeinit)1>(swift::RefCountBitsT<(swift::RefCountInlinedness)1>, unsigned int) + 156
frame #5: 0x00000001d2f5f584 SwiftUICore`closure #1 () -> () in SwiftUI.ObjectLocation.set(_: τ_0_1, transaction: SwiftUI.Transaction) -> () + 132
frame #6: 0x00000001d2f5f6b0 SwiftUICore`partial apply forwarder for closure #1 () -> () in SwiftUI.ObjectLocation.set(_: τ_0_1, transaction: SwiftUI.Transaction) -> () + 28
frame #7: 0x00000001d2801da8 SwiftUICore`generic specialization <()> of closure #1 () throws -> τ_0_0 in SwiftUI.withTransaction<τ_0_0>(SwiftUI.Transaction, () throws -> τ_0_0) throws -> τ_0_0 + 296
frame #8: 0x00000001d2f5f4d8 SwiftUICore`SwiftUI.ObjectLocation.set(_: τ_0_1, transaction: SwiftUI.Transaction) -> () + 336
frame #9: 0x00000001d2c42468 SwiftUICore`SwiftUI.LocationBox.set(_: τ_0_0.Value, transaction: SwiftUI.Transaction) -> () + 148
frame #10: 0x00000001d2c42c84 SwiftUICore`protocol witness for SwiftUI.Location.set(_: τ_0_0.Value, transaction: SwiftUI.Transaction) -> () in conformance SwiftUI.LocationBox<τ_0_0> : SwiftUI.Location in SwiftUI + 20
frame #11: 0x00000001d2c42e90 SwiftUICore`SwiftUI.ProjectedLocation.set(_: τ_0_1.Projected, transaction: SwiftUI.Transaction) -> () + 196
frame #12: 0x00000001d2c42468 SwiftUICore`SwiftUI.LocationBox.set(_: τ_0_0.Value, transaction: SwiftUI.Transaction) -> () + 148
frame #13: 0x00000001d2cf2fe8 SwiftUICore`SwiftUI.Binding.ScopedLocation.set(_: τ_0_0, transaction: SwiftUI.Transaction) -> () + 28
frame #14: 0x00000001d2c42468 SwiftUICore`SwiftUI.LocationBox.set(_: τ_0_0.Value, transaction: SwiftUI.Transaction) -> () + 148
frame #15: 0x00000001d2cf3190 SwiftUICore`function signature specialization <Arg[0] = Owned To Guaranteed> of SwiftUI.Binding.wrappedValue.setter : τ_0_0 + 32
frame #16: 0x00000001d2cf12c0 SwiftUICore`SwiftUI.Binding.wrappedValue.setter : τ_0_0 + 28
frame #17: 0x00000001d1d0e538 SwiftUI`closure #1 () -> () in SwiftUI.NavigationColumnState.popAllForSelectionChange(popReplacedRoots: Swift.Bool) -> SwiftUI.NavigationState.RequestResults + 524
frame #18: 0x00000001d281be58 SwiftUICore`partial apply forwarder for reabstraction thunk helper from @callee_guaranteed (@guaranteed Swift.Dictionary<__C.NSAttributedStringKey, Any>, @unowned __C._NSRange, @unowned Swift.UnsafeMutablePointer<ObjectiveC.ObjCBool>) -> () to @escaping @callee_guaranteed (@guaranteed Swift.Dictionary<__C.NSAttributedStringKey, Any>, @unowned __C._NSRange, @unowned Swift.UnsafeMutablePointer<ObjectiveC.ObjCBool>) -> () + 20
frame #19: 0x00000001d2b3b64c SwiftUICore`static SwiftUI.Update.dispatchActions() -> () + 1080
frame #20: 0x00000001d2b3ac4c SwiftUICore`static SwiftUI.Update.end() -> () + 108
frame #21: 0x00000001d18daf44 SwiftUI`closure #1 (Swift.Optional<Swift.UnsafeMutableRawPointer>, Swift.Double, Swift.UnsafePointer<__C._UIUpdateTiming>) -> () in static SwiftUI.UIKitUpdateCycle.addPreCommitObserver(() -> ()) -> () + 168
frame #22: 0x00000001d18dafbc SwiftUI`reabstraction thunk helper from @escaping @callee_guaranteed (@unowned Swift.Optional<Swift.UnsafeMutableRawPointer>, @unowned Swift.Double, @unowned Swift.UnsafePointer<__C._UIUpdateTiming>) -> () to @escaping @callee_unowned @convention(block) (@unowned Swift.Optional<Swift.UnsafeMutableRawPointer>, @unowned Swift.Double, @unowned Swift.UnsafePointer<__C._UIUpdateTiming>) -> () + 64
frame #23: 0x0000000185030388 UIKitCore`_UIUpdateSequenceRun + 76
frame #24: 0x00000001859d22e8 UIKitCore`schedulerStepScheduledMainSection + 168
frame #25: 0x00000001859d1720 UIKitCore`runloopSourceCallback + 80
frame #26: 0x000000018041b324 CoreFoundation`__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 24
frame #27: 0x000000018041b26c CoreFoundation`__CFRunLoopDoSource0 + 172
frame #28: 0x000000018041a9d0 CoreFoundation`__CFRunLoopDoSources0 + 232
frame #29: 0x00000001804150b0 CoreFoundation`__CFRunLoopRun + 788
frame #30: 0x0000000180414960 CoreFoundation`CFRunLoopRunSpecific + 536
frame #31: 0x0000000190183b10 GraphicsServices`GSEventRunModal + 160
frame #32: 0x0000000185aa2b40 UIKitCore`-[UIApplication _run] + 796
frame #33: 0x0000000185aa6d38 UIKitCore`UIApplicationMain + 124
frame #34: 0x00000001d1e2eab4 SwiftUI`closure #1 (Swift.UnsafeMutablePointer<Swift.Optional<Swift.UnsafeMutablePointer<Swift.Int8>>>) -> Swift.Never in SwiftUI.KitRendererCommon(Swift.AnyObject.Type) -> Swift.Never + 164
frame #35: 0x00000001d1e2e7dc SwiftUI`SwiftUI.runApp<τ_0_0 where τ_0_0: SwiftUI.App>(τ_0_0) -> Swift.Never + 84
frame #36: 0x00000001d1b70c8c SwiftUI`static SwiftUI.App.main() -> () + 148
frame #37: 0x0000000104333df0 DoubleNav.debug.dylib`static DoubleNavApp.$main() at <compiler-generated>:0
frame #38: 0x0000000104333ea0 DoubleNav.debug.dylib`main at DoubleNavApp.swift:11:8
frame #39: 0x00000001048f9410 dyld_sim`start_sim + 20
frame #40: 0x000000010440e154 dyld`start + 2476
Thanks for any tips!