Почему обновление переменной в наблюдаемом объекте не обновляет представление? - PullRequest
0 голосов
/ 05 ноября 2019

Я новичок в 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;
    }


}

Если я попытался обновить привязку 'signInSuccess' в loginView, он может успешно обновить представление для mainView. Однако есть ли способ, которым я могу обновить signInSuccess внутри наблюдаемого объекта, который также обновляет ContentView до MainView?

Ответы [ 2 ]

1 голос
/ 06 ноября 2019

Да, вы просто измените код просмотра следующим образом. Привязка на самом деле не нужна.

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())
0 голосов
/ 06 ноября 2019

Если вы хотите использовать переменную окружения, вы должны объявить ее в 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 как закрытый (установленный), чтобы его можно было установить только из класса и читать только изв другом месте:

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

    }
}
...