SwiftUI: переменная @State никогда не обновляется из @Published

Я пытаюсь вызвать предупреждение, когда в модели возникает ошибка, но оно никогда не обновляется, чтобы показать предупреждение:

Вот моя реализация в представлении:

      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"))
        )}
    }
}

Вот мои модели:

      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)
        }
    }
}

Любой из вас знает, почему showAlertпеременная никогда не обновляется?

Я буду очень признателен за вашу помощь

2 ответа

В вашем текущем коде вы устанавливаете ContentView's к 's в этот момент времени :

      init() {
  viewModel = ViewModel()
  showAlert = viewModel.showAlert //<-- assignment at the time of init
}

Это означает, что это falseна момент назначения. Потому что это просто назначение другому Bool, нет механизма для обновления, если ViewModelх showAlertизменения.

Самое простое решение - избавиться от @Stateпеременная и наблюдать за @Publishedнедвижимость напрямую:

      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"))
        )}
    }
}

Избавьтесь от объекта модели представления, это основная проблема. Мы не используем их в SwiftUI. Мы используем структуру View для данных представления и @Stateа также @Bindingобертки свойств, чтобы структура вела себя как объект, поэтому вам нужно сначала изучить это.

Также я не думаю, что вам нужен Combine для того, что вы пытаетесь сделать, потому что вы ничего не комбинируете, используя combineLatestи т. д., но когда мы используем его в SwiftUI, мы не используем sinkили же store, вместо этого мы assignконец трубопровода к @Published.

Пример:

      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
        }
    }
}
Другие вопросы по тегам