SwiftUI:@State变量从@Published永远不会更新

3

我希望当模型出现错误时能够触发警报,但是它从未更新以显示警报:

这是我在视图中的实现:

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个回答

4

在您当前的代码中,您将ContentViewshowAlert设置为ViewModel那个时刻showAlert

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

意思是,在赋值时它是false。因为只是将一个Bool分配给另一个Bool,所以如果ViewModelshowAlert更改,就没有保持更新的机制。
最简单的解决方案是摆脱您的@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"))
        )}
    }
}

我们想让它成为@ObservedObject,换句话说,每当SwiftUI更新ContentView的body时都会重新实例化吗? 也许在这里使用StateObject更好,你认为呢? - OhadM

3

最好移除视图模型对象,因为在SwiftUI中我们不需要这些,因为View结构体持有视图数据,@State@Binding属性包装器使结构体的行为类似于对象。

此外,我认为你不需要使用Combine来完成你想做的事情,因为你没有使用combineLatest等来组合任何内容,但是当我们在SwiftUI中使用它时,我们不使用sinkstore,而是将管道的末端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
        }
    }
}

你能发一个例子吗? - user2924482
@user2924482 发布了: - malhal
但在我的情况下,警报是由模型/后端的问题触发的。您如何应用此功能以在模型/后端中显示警报? - user2924482
1
你只需要像showAlert函数一样拥有一个函数,它调用后端并在返回错误时更新@State以显示错误。 - malhal

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接