swift 从另一个observableObject更改observableObject的属性

dl5txlt9  于 2022-10-31  发布在  Swift
关注(0)|答案(1)|浏览(226)

存在以下性质的问题:有必要为应用程序创建一个授权窗口,这是我在以下实现中找到的最合理的解决方案(我必须这样做,因为mainView有一个tabView,如果它在navigationView中,则会出现错误的行为)

struct ContentView: View {

@EnvironmentObject var vm: AppSettings

var body: some View {
    if vm.isLogin {
        MainView()
    } else {
        LoginView()
    }
}

AppSettings看起来像这样:

struct MyApp: App {

    @StateObject var appSetting = AppSettings()

    var body: some Scene {
        WindowGroup {
            ContentView()
                .environmentObject(appSetting)
        }
    }
}
class AppSettings: ObservableObject {
    @Published var isLogin = false
}

默认情况下,将向用户显示一个授权窗口,如下所示:

struct LoginView: View {
    @StateObject var vm = LoginViewModel()
    var body: some View {
        NavigationView {
            VStack {
                TextField("Email", text: $vm.login)
                TextField("Password", text: $vm.password)

                Button {
                    vm.auth()
                } label: {
                    Text("SignIn")
                }
            }
        }
    }
}

最后,loginViewModel看起来像这样:

class LoginViewModel: ObservableObject {

    @Published var login = ""
    @Published var password = ""

  //@Published var appSettings = AppSettings() -- error on the first screenshot
    //or
  //@EnvironmentObject var appSettings: AppSettings -- error on the second screenshot

    func auth() {
        UserAPI().Auth(req: LoginRequest(email: login, password: password)) { response, error in
            if let err = error {
                // Error Processing
            } else if let response = response {
                Defaults.accessToken = response.tokens.accessToken
                Defaults.refreshToken = response.tokens.refreshToken
                self.appSettings.isLogin = true
            }
        }
    }
}

1个错误-Accessing StateObject's object without being installed on a View. This will create a new instance each time
2个错误-No ObservableObject of type AppSettings found. A View.environmentObject(_:) for AppSettings may be missing as an ancestor of this view
我请求帮助,我就是找不到两个observableObject交互的方法。我不得不将所有的逻辑插入到按钮的action中来实现这样的功能
除此功能外,还计划通过在各种情况下将isLogin变量更改为false来实现退出帐户,或使用其他环境变量轻松实现其他功能
为了便于解释情况,我们特意简化了这个例子

yi0zb3m4

yi0zb3m41#

我认为在顶层只使用LoginViewModel是解决这个问题最简单的方法。但是如果你想同时保留两个,你可以用.onChanged修改器来同步它们。

class LoginViewModel: ObservableObject {

    @Published var login = ""
    @Published var password = ""

    @Published var isLogin = false

    func auth() {
        UserAPI().Auth(req: LoginRequest(email: login, password: password)) { response, error in
            if let err = error {
                // Error Processing
            } else if let response = response {
                Defaults.accessToken = response.tokens.accessToken
                Defaults.refreshToken = response.tokens.refreshToken
                isLogin = true
            }
        }
    }
}

struct LoginView: View {
    @StateObject var vm = LoginViewModel()
    // grab the AppSettings from the environment
    @EnvironmentObject var appSetting: AppSettings
    var body: some View {
        NavigationView {
            VStack {
                TextField("Email", text: $vm.login)
                TextField("Password", text: $vm.password)

                Button {
                    vm.auth()
                } label: {
                    Text("SignIn")
                }
                // synchronise the viewmodels here
                .onChange(of: vm.isLogin) { newValue in
                    appSetting.isLogin = newValue
                }
            }
        }
    }
}

相关问题