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 ()
I'm seeing the same warning, as well as significantly decreased performance in my SwiftUI app on iOS 16 (none of these issues on iOS 15). Unsure if these are due to to an Xcode/iOS bug or if I'm actually doing something wrong.
The problem comes from using a Binding variable as a ObservableObject, in ios 16 it gives you this warning not to use Bindings with Observables. For a good explanation of how and why, here's a link to " Rebeloper - Rebel Developer" video on YouTube.
https://youtu.be/3a7tuhVpoTQ
Hope this will help.
I send feedback to Apple and received answer to retest this with iOS 16.2. After retesting this is not longer shown as a warning so it looks like Apple has fixed it behind the scenes.