I'm seeing NavigationPath retaining objects after they've been popped off the path.
It is showing up as:
SwiftUI.(ItemBox in $10b3430a8)<Project.ViewModel>
NavigationPath_ItemBoxBase
_TtCs12_SwiftObject
If I follow that path up it eventually ends with:
SwiftUIEnvironmentWrapper
Looks like that is being used/held/managed by something like:
<SwiftUI.(TypedElement in $10b356118)<SwiftUI.(EnvironmentPropertyKey in $10b35f1b0)<SwiftUI._NavigationAuthority_State.Key>> 0x600003078800> [128] +88
Basically I have a class view model that subscribes to hashable and gets pushed on the path. Navigation works correctly. I pop that object off the path, correctly animates back and I'm left at the root view.
Take a memory snapshot and that object is still alive, along with everything it's holding onto. If I inspect the navigation path it has a 0 count.
Any idea how I can free this object from its environment object prison?
Post
Replies
Boosts
Views
Activity
After updating to Xcode 14.0 beta 5 (14A5294e) I'm seeing runtime warnings on iOS when simply changing a published variable from within a button's action.
I'm wondering if this is a false positive on the warning or if there is a new pattern we're supposed to be following here.
This appears to only happen on iOS. The same reproducing code does not output that warning while running on macOS.
Here's a contrived yet complete example that reproduces it on an iPhone 13 Pro simulator while running Xcode 14 beta 5. Does not reproduce the warning when running on Ventura.
class ViewModel: ObservableObject {
@Published var sheetVM: SheetVM?
func showSheet() {
sheetVM = SheetVM(delegate: self)
}
}
extension ViewModel: SheetDelegate {
func close() {
sheetVM = nil
}
}
class SheetVM: ObservableObject, Identifiable {
weak var delegate: SheetDelegate?
init(delegate: SheetDelegate) {
self.delegate = delegate
}
func close() {
delegate?.close()
}
}
protocol SheetDelegate: AnyObject {
func close()
}
struct ContentView: View {
@ObservedObject
var viewModel: ViewModel
var body: some View {
VStack {
Button {
viewModel.showSheet()
} label: {
Text("Show Sheet")
}
}
.padding()
.sheet(item: $viewModel.sheetVM) { sheetVM in
SheetView(sheetVM: sheetVM)
}
}
}
struct SheetView: View {
let sheetVM: SheetVM
var body: some View {
NavigationView {
Text("Sheet View")
.toolbar {
ToolbarItem(placement: .automatic) {
Button {
sheetVM.close()
} label: {
Text("Done")
.fontWeight(.semibold)
}
}
}
}
}
}
Here's the warning and trace while tapping done on the sheet:
warning run: Publishing changes from within view updates is not allowed, this will cause undefined behavior.
Thread 1
#0 0x0000000000000000 in ___lldb_unnamed_symbol155969 ()
#1 0x0000000000000000 in ___lldb_unnamed_symbol155968 ()
#2 0x0000000000000000 in ___lldb_unnamed_symbol155988 ()
#3 0x0000000000000000 in ___lldb_unnamed_symbol180158 ()
#4 0x0000000000000000 in ObservableObjectPublisher.Inner.send() ()
#5 0x0000000000000000 in ObservableObjectPublisher.send() ()
#6 0x0000000000000000 in PublishedSubject.send(_:) ()
#7 0x0000000000000000 in specialized static Published.subscript.setter ()
#8 0x0000000000000000 in static Published.subscript.setter ()
#9 0x0000000000000000 in ViewModel.sheetVM.setter ()
#10 0x0000000000000000 in key path setter for ViewModel.sheetVM : ViewModel ()
#11 0x0000000000000000 in NonmutatingWritebackBuffer.__deallocating_deinit ()
#12 0x0000000000000000 in _swift_release_dealloc ()