Home > Net >  SwiftUI: @State variable never get updated from @Published
SwiftUI: @State variable never get updated from @Published

Time:02-05

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

CodePudding user response:

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"))
        )}
    }
}
  •  Tags:  
  • Related