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 ()
Selecting any option will automatically load the page
Post
Replies
Boosts
Views
Activity
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?