【问题标题】:Why update variable in observable object does not update the view?为什么可观察对象中的更新变量不会更新视图?
【发布时间】:2019-11-05 19:51:03
【问题描述】:

我是 SwiftUI 的新手。学习@State、@Binding、@EnvironmentObject 等新属性。

我目前正在开发登录模板,在可观察对象中定义一个绑定@Published 变量,它允许在登录页面和主页之间切换。但是,当我更新可观察对象内的变量时,主页不会显示。它仍然在登录页面中。我的代码中缺少什么?


struct ContentView: View {

    @EnvironmentObject var loginViewModel: LoginViewModel



    var body: some View {

        return Group {
            if loginViewModel.signInSuccess {
                MainPageView()
            }
            else {
                LoginView(signInSuccess: $loginViewModel.signInSuccess).environmentObject(LoginViewModel())
            }
        }


    }


}



final class LoginViewModel: ObservableObject  {
      @Published var signInSuccess:Bool = false;

      func performLogin() {
           signInSuccess = true;
      }

}


struct LoginView: View {

    @EnvironmentObject var loginViewModel: LoginViewModel

    @Binding var signInSuccess: Bool;

    var body: some View {

        Button(action: submit) {
                Text("Login")
                    .foregroundColor(Color.white)

        }

    }

    func submit() {
        loginViewModel.performLogin()
        // signInSuccess = true;
    }


}

如果我尝试在 loginView 中更新绑定“signInSuccess”,它可以成功地将视图更新到 mainView。但是,有没有一种方法可以更新 Observable 对象中的 signInSuccess,同时将 ContentView 更新为 MainView?

【问题讨论】:

    标签: ios swift authentication data-binding swiftui


    【解决方案1】:

    是的,您只需将视图代码更改如下。 绑定实际上是没有必要的。

    struct ContentView: View {
    
    @EnvironmentObject var loginViewModel: LoginViewModel 
    
    var body: some View {
    
        return Group {
            if loginViewModel.signInSuccess {
               MainPageView()()
            }
            else {
                LoginView(signInSuccess: $loginViewModel.signInSuccess).environmentObject(self.loginViewModel)
            }
        }
    
    
    }
    
    
    }
    
    
       window.rootViewController = UIHostingController(rootView:    ContentView().environmentObject(LoginViewModel())
    

    【讨论】:

    • 感谢您的正确建议。我对 environmentObject 有了更好的了解。
    【解决方案2】:

    如果你想使用环境变量,你必须在你的 SceneDelegate 中声明它并在 ContontentView 上设置它:

    class SceneDelegate: UIResponder, UIWindowSceneDelegate {
    
        var window: UIWindow?
    
        var loginViewModel = LoginViewModel()
    
        func scene(_ scene: UIScene,
                   willConnectTo session: UISceneSession,
                   options connectionOptions: UIScene.ConnectionOptions) {
    
    
            let contentView = ContentView()
            if let windowScene = scene as? UIWindowScene {
                let window = UIWindow(windowScene: windowScene)
                window.rootViewController = HostingViewController(rootView: contentView.environmentObject(loginViewModel))
                self.window = window
                window.makeKeyAndVisible()
            }
        }
        // etc.
    

    然后在您的 ContenView 中,您无需在 LoginView 上以任何方式设置它,因为它由环境持有:

    struct ContentView: View {
    
        @EnvironmentObject var loginViewModel: LoginViewModel
    
        var body: some View {
    
            return Group {
                if loginViewModel.signInSuccess {
                    MainPageView()
                } else {
                    LoginView()
                }
            }
        }
    }
    

    在您的模型中,确保将您的 signInSuccess 声明为 private(set),以便它只能从类中设置并且只能从其他地方读取:

    final class LoginViewModel: ObservableObject  {
          @Published private(set) var signInSuccess:Bool = false;
    
          func performLogin() {
               signInSuccess = true;
          }
    
    }
    

    最后,在 LoginView 中,您只需要包含 @EnvironmentObject,其他一切都可以工作。

    struct LoginView: View {
    
        @EnvironmentObject var loginViewModel: LoginViewModel
    
        var body: some View {
            Button(action: { self.loginViewModel.performLogin() }) {
                    Text("Login")
                        .foregroundColor(Color.white)
            }
    
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-03-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-07-25
      • 1970-01-01
      相关资源
      最近更新 更多