I'm trying to trigger an alert when is an error in the model but it never get updated to show the alert:
Here is my implementation in the view:
struct ContentView: View {
@ObservedObject var viewModel: ViewModel
@State var showAlert = false
init() {
viewModel = ViewModel()
showAlert = viewModel.showAlert
}
var body: some View {
NavigationView {
Text("Hello, world!")
.padding()
}
.alert(isPresented: $showAlert) {
Alert(title: Text("This works"),
message: Text("Hello"),
dismissButton: .default(Text("got it"))
)}
}
}
Here is my models:
class ViewModel: ObservableObject {
@Published var showAlert = false
var cancellables = Set<AnyCancellable>()
init() {
DoSomething.shared.showAlert.sink { _ in
print("got new Value")
} receiveValue: {[weak self] value in
print("value")
self?.showAlert = value
}.store(in: &cancellables)
}
}
class DoSomething {
let showAlert = PassthroughSubject<Bool, Never>()
static let shared = DoSomething()
private init() {
checkToShowAlert()
}
func checkToShowAlert() {
DispatchQueue.main.asyncAfter(deadline: .now() + 5) { [weak self] in
print("change value")
self?.showAlert.send(true)
}
}
}
Any of you knows why the showAlert
variable it never gets updated?
I'll really appreciate your help
In your current code, you're setting ContentView
's showAlert
to the ViewModel
's showAlert
at that point in time :
init() {
viewModel = ViewModel()
showAlert = viewModel.showAlert //<-- assignment at the time of init
}
Meaning, it's false
at the time of assignment. Because it's just a Bool
getting assigned to another Bool
, there's no mechanism to keep it updated if ViewModel
's showAlert
changes.
The simplest solution is to get rid of your @State
variable and observe the @Published
property directly:
struct ContentView: View {
@ObservedObject var viewModel: ViewModel = ViewModel()
var body: some View {
NavigationView {
Text("Hello, world!")
.padding()
}
.alert(isPresented: $viewModel.showAlert) {
Alert(title: Text("This works"),
message: Text("Hello"),
dismissButton: .default(Text("got it"))
)}
}
}
Get rid of the view model object, that's the main problem. We don't use those in SwiftUI. We use the View struct for the view data and the @State
and @Binding
property wrappers to make the struct behave like an object so you'll need to learn that first.
Also I don't think you need Combine for what you are trying to do because you aren't combining anything using combineLatest
etc, but when we do use it in SwiftUI we don't use sink
or store
, instead we assign
the end of the pipeline to an @Published
.
Example:
struct ContentView: View {
@State var isPresented = false
var body: some View {
NavigationView {
VStack{
Text("Hello, world!")
.padding()
Button("Show Alert") {
showAlert()
}
}
}
.alert(isPresented: $isPresented) {
Alert(title:Text("This works"),
message: Text("Hello"),
dismissButton: .default(Text("got it"))
)}
}
func showAlert() {
DispatchQueue.main.asyncAfter(deadline: .now() + 5) {
isPresented = true
}
}
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.