When dismissing a fullScreenCover using a variable inside an ObservableObject (lines commented with 1.-) it shows the "Publishing changes from within view updates is not allowed, this will cause undefined behavior." message in the console, but using a @State variable (lines commented with 2.-) does not show the warning. I do not understand why.
Here is the code:
import SwiftUI
final class DismissWarningVM: ObservableObject {
@Published var showAnotherView = false
}
struct DismissWarningView: View {
@StateObject private var dismissWarningVM = DismissWarningVM()
@State private var showAnotherView = false
var body: some View {
VStack {
HStack {
Spacer()
Button {
// 1.- This line provokes the warning
dismissWarningVM.showAnotherView = true
// 2.- This line DO NOT provokes the warning
//showAnotherView = true
} label: {
Text("Show")
}
}
.padding(.trailing, 20)
Spacer()
Text("Main view")
Spacer()
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
.background(.white)
// 1.- This line provokes the warning
.fullScreenCover(isPresented: $dismissWarningVM.showAnotherView) {
// 2.- This line DO NOT provokes the warning
//.fullScreenCover(isPresented: $showAnotherView) {
AnotherView()
}
}
}
struct AnotherView: View {
@Environment(\.dismiss) var dismiss
var body: some View {
VStack(spacing: 30) {
Text("Another view")
Button {
dismiss()
} label: {
Text("Dismiss")
.foregroundColor(.red)
}
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
.ignoresSafeArea()
}
}
struct DismissWarningView_Previews: PreviewProvider {
static var previews: some View {
DismissWarningView()
}
}
@StateObjectisn't designed for view model objects. In SwiftUI theViewstruct is the view model already you don't another one. Remember SwiftUI is diffing these structs and creating/updating/removing UIView objects automatically for us. If you use view model objects then you'll haveviewModel object -> View struct -> UIView objectwhich is a big mess and will lead to bugs.@StateObjectis designed for when you need a reference type in an@Statewhich isn't very often nowadays given we have.taskand.task(id:)for asynchronous features.You can achieve what you need like this: