SwiftUI @State 变量不更新视图

时间:2021-05-17 13:50:44

标签: swift swiftui

我对 swift 开发非常陌生,我正在尝试遵循多个不同的在线教程来尝试构建登录页面。不幸的是,所有不同的视图和模型都没有很好地整合在一起,我遇到了一些问题。

除了 ErrorView 显示之外,下面的代码似乎有效。当变量 alerterror 是 @Published 变量时,此代码不会编译。它给了我错误“无法为表达式生成诊断”。当我将它们都更改为 @State 变量时,它们不会更新视图。

class AppViewModel: ObservableObject{
    @Published var signedIn = false
    @Published var alert = false;
    @Published var error = ""
    let auth = Auth.auth();

    func signIn(email: String, password: String){
        auth.signIn(withEmail: email, password: password) { [weak self] result, error in
            guard result != nil, error == nil else{
                self?.error = error!.localizedDescription
                print(error!.localizedDescription)
                self?.alert.toggle()
                return
            }
            
            DispatchQueue.main.async {
                self?.signedIn = true
            }
        }
    }
}

struct SignInView: View {
    @State var email = ""
    @State var password = ""
    @EnvironmentObject var viewModel: AppViewModel
       
    var body: some View {      
        VStack {
            if viewModel.alert {
                //SHOW ERROR        
                ErrorView(alert: viewModel.$alert, error: viewModel.$error)
                Text("errors")        
            }
            //SHOW SIGN IN FORM
            //THERE IS CODE HERE TO CALL THE AUTH FUNCTIONS VIA BUTTONS ETC BUT APPARENTLY I'M NOT ALLOWED TO PUT THE WHOLE FILE IN THIS QUESTION
        }
    }
}

如果我使用已发布的变量,我会在 Failed to produce diagnostic for expression; please file a bug report 处收到错误 var body: some View。如果我使用状态变量,则永远不会显示 ErrorView。

2 个答案:

答案 0 :(得分:4)

您应该将 viewModel.$alert 更改为 $viewModel.alert

当您使用 @State 时,viewModel.$alert 的类型是 Binding<Bool>。现在您已将其更改为 @Published,就像它应该的那样,该类型现在是 Published<Bool>.Publisher

当您使用 $viewModel.alert 时,类型再次正确为 Binding<Bool>

答案 1 :(得分:1)

改变这个

ErrorView(alert: viewModel.$alert, error: viewModel.$error)

到这里

ErrorView(alert: $viewModel.alert, error: $viewModel.error)

提示

几乎总是,您应该将任何变量移动到您的视图模型中。例如,您的视图中有 email and password 作为 @State 变量。将它们移动到您的视图模型更有意义。为什么?您稍后可能需要在 VM 本身的函数或方法中访问它们。如果数据已经存在,则处理起来要容易得多。在您看来,您可以使用 Text(viewModel.email)Text(viewModel.password) 访问它。但是,如果您需要验证这一点,在您的视图模型中,它将很容易访问。