Reputation: 781
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()
}
}
Upvotes: 2
Views: 108
Reputation: 781
Fixed. It was a problem of the XCode version. I was trying with 14.0.1 version but after updating to 14.1 version the warning is no longer shown
Upvotes: 0
Reputation: 30746
@StateObject
isn't designed for view model objects. In SwiftUI the View
struct 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 have viewModel object -> View struct -> UIView object
which is a big mess and will lead to bugs. @StateObject
is designed for when you need a reference type in an @State
which isn't very often nowadays given we have .task
and .task(id:)
for asynchronous features.
You can achieve what you need like this:
struct WarningConfig {
var isPresented = false
// mutating func someLogic() {}
}
struct SomeView: View {
@State private var config = WarningConfig()
...
.fullScreenCover(isPresented: $config.isPresented) {
WarningView(config: $config)
Upvotes: -3