在子视图中更新ObservableObject的@Published变量

时间:2019-09-05 03:27:49

标签: swift swiftui swift5

我在ObservableObject类中有一个已发布的变量isLoggedIn,如下所示:

import Combine

class UserAuth: ObservableObject{
    @Published var isLoggedIn: Bool = false
}

我想在特定视图(LoginView)中将此变量更新为true。此变量确定是否显示用户视图,具体取决于用户是否登录:

struct ContentView: View {
    @ObservedObject  var userAuth = UserAuth()
    var body: some View {
        Group{
            if(userAuth.isLoggedIn){
                MainView()
            }else{
                AccountView()
            }
        }
    }
}

因为userAuth.isLoggedIn为false(我尚未登录),所以显示了AccountView。

AccountView:

struct AccountView: View {
    @State private var toggleSheet = false
    var body: some View {
        VStack {
            Spacer()
            Button(action: {
                self.toggleSheet.toggle()
            }){
                Text("Toggle Modal")
                    .padding()
                    .foregroundColor(Color.white)
                    .background(Color.blue)
                    .cornerRadius(10)
            }
            .sheet(isPresented: self.$toggleSheet){
                LoginView()
            }
            Spacer()
        }
    }
}

每当用户按下按钮时,都会显示LoginView Modal:

struct LoginView: View {
    var body: some View {
        VStack{
            Button(action: {
                return self.login()
            }){
                Text("Log in")
                    .padding()
                    .foregroundColor(Color.white)
                    .background(Color.green)
                    .cornerRadius(10)
            }
        }
    }

    func login(){
        // update UserAuth().isLoggedIn to TRUE
    }
}

在LoginView中有一个按钮,我想要的逻辑是供用户按下该按钮,调用login()并将该函数userAuth.isLoggedIn设置为true。实现此目的的最佳方法是什么?

我尝试直接更改该值,但出现以下错误:

Publishing changes from background threads is not allowed; make sure to publish values from the main thread (via operators like receive

2 个答案:

答案 0 :(得分:5)

尝试像这样将代码嵌入DispatchQueue.main.async:

func login(){
    DispatchQueue.main.async {
        update UserAuth().isLoggedIn to TRUE
    }
}

答案 1 :(得分:1)

一种可能性是将UserAuth中的ContentView对象作为EnvironmentObject插入子视图中。

struct ContentView: View {
    @ObservedObject var userAuth = UserAuth()
    var body: some View {
        Group {
            if userAuth.isLoggedIn {
                MainView()
            } else {
                AccountView()
                .environmentObject(userAuth)
            }
        }
    }
}

现在userAuth及其在其所有子视图(例如AccountView)中均可访问:

LoginView

可能有必要将EnvironmentObject手动插入struct LoginView: View { // Access to the environment object @EnvironmentObject private var userAuth: UserAuth var body: some View { VStack { Button(action: { return self.login() }) { Text("Log in") .padding() .foregroundColor(Color.white) .background(Color.green) .cornerRadius(10) } } } func login() { // Update the value on the main thread DispatchQueue.main.async { self.userAuth.isLoggedIn = true } } } 中。您可以通过在LoginView中访问它并将其插入AccountView中来做到这一点:

LoginView

进一步阅读
WWDC 2019 Video | Hacking with Swift Example