【问题标题】:Why does the Navigation Bar from the View still remain after Signing Out a User为什么退出用户后视图中的导航栏仍然存在
【发布时间】:2021-11-02 15:26:17
【问题描述】:

我正在开发一个非常简单的应用程序,以尝试将我的注意力集中在 SwiftUI 和 Firebase 上。我有一个登录视图、一个注册视图和用户登录后显示的 FirstView。

一旦用户登录并点击 SignOut 按钮,仅在 FirstView 中可见的导航栏突然也出现在 LoginView 上。这不应该发生,我试图理解为什么会发生这种情况。也许我没有正确关闭 FirstView?

作为一个附带问题,我还遇到了一个问题,即我的用户数据在登录后在 FirstView 上显示/更新,但视图内字段的文本更改之间存在明显延迟。

任何帮助将不胜感激。

这里是相关代码...

@main
struct AWSupportLoggerApp: App {
    
    @UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
    
    @StateObject var viewModel = AppViewModel()
    
    var body: some Scene {
        WindowGroup {
            ContentView()
                .environmentObject(viewModel)
        }
    }
    
    
    
    class AppDelegate:NSObject,UIApplicationDelegate{
        func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
            FirebaseApp.configure()
            return true
        }
    }
    
    
}



    class AppViewModel: ObservableObject {
        private var db = Firestore.firestore()
        
        @Published var userInfo: User?
        @Published var signedIn: Bool = false
        
        var handle: AuthStateDidChangeListenerHandle?
        let authRef = Auth.auth()
        
        var authHandle : AuthStateDidChangeListenerHandle?
        var rootInfoCollection : CollectionReference!
        var userIdRef = ""
        
        
        
        func fetchUserData(){
            db.collection("Users").document("\(userIdRef)").getDocument { document, error in
                // Check for error
                if error == nil {
                    // Check that this document exists
                    if document != nil && document!.exists {
                        
                        self.userInfo = document.map { (documentSnapshot) -> User in
                            let data = documentSnapshot.data()
                            
                            let uid = data?["uid"] as? UUID ?? UUID()
                            let company = data?["company"] as? String ?? ""
                            let name = data?["name"] as? String ?? ""
                            let admin = data?["admin"] as? Bool ?? false
                            let photo = data?["photo"] as? String ?? ""
                            
                            return User(uid: uid, company: company, name: name, admin: admin, photo: photo)
                        }
                    }
                }
            }
            
        }
        
        func listen(){
            handle = authRef.addStateDidChangeListener({ auth, user in
                print(user?.email ?? "No User Found")
                
                if let user = auth.currentUser {
                    self.userIdRef = user.uid
                    self.rootInfoCollection = Firestore.firestore().collection("/Users/")
                    
                    DispatchQueue.main.async {
                        self.fetchUserData()
                    }
                    
                    self.signedIn = true
                    
                } else {
                    self.signedIn = false
                }
            })
            
        }
        
        func signIn(email: String, password: String){
            authRef.signIn(withEmail: email, password: password) { result, error in
                guard result != nil, error == nil else {
                    return
                }
            }
        }
        
        func signOut(){
            do {
                try authRef.signOut()
            } catch {
                print(error)
            }
        }
        
        func signUp(email: String, password: String, company: String, name: String, admin: Bool, photo: String){
            authRef.createUser(withEmail: email, password: password) { result, error in
                
                guard result != nil, error == nil else {
                    return
                }
                
                let db = Firestore.firestore()
                
                //Success
                db.collection("Users").document("\(result!.user.uid)").setData(["company" : "\(company)", "name" : "\(name)", "admin" : admin, "photo" : "\(photo)", "uid":result!.user.uid]) { error in
                    if error != nil {
                        print(error!)
                    }
                }
                
            }
        }
        
        
        func unbind() {
            if let handle = handle {
                authRef.removeStateDidChangeListener(handle)
            }
        }
        
    }
    
    
    struct ContentView: View {
        @EnvironmentObject var viewModel: AppViewModel
        
        var body: some View {
            
            NavigationView {
                if viewModel.signedIn {
                     FirstView()
                } else {
                    //.onAppear method is used for keyboard management (See Misc Functions...)
                    SignInView()
                        .onAppear(perform: UIApplication.shared.addTapGestureRecognizer)
                }
            }
            .onAppear {
                viewModel.listen()
            }
        }
    }
    
    struct FirstView: View {
        @EnvironmentObject private var appViewModel: AppViewModel
    
        var body: some View {
    
            VStack{
                Spacer()
                VStack(spacing: 50){
                    
                    NavigationLink(destination: Text("Test")){
                        awButton(content: "Request Support", backColor: Color(#colorLiteral(red: 0, green: 0.723585546, blue: 0.9907287955, alpha: 1)))
                            .shadow(color: Color.primary.opacity(0.5), radius: 20, x: 0, y: 20)
                            .rotation3DEffect(Angle(degrees:10), axis: (x: 10.0, y: 0, z: 0))
                    }
    
                    NavigationLink(destination: Text("Test")){
                        awButton(content: "Request Quote", backColor: Color(#colorLiteral(red: 0.9372549057, green: 0.3490196168, blue: 0.1921568662, alpha: 1)))
                            .shadow(color: Color.primary.opacity(0.5), radius: 20, x: 0, y: 20)
                            .rotation3DEffect(Angle(degrees:10), axis: (x: 10.0, y: 0, z: 0))
                    }
    
                    NavigationLink(destination: Text("Test")){
                        awButton(content: "Ticket Status", backColor: Color(#colorLiteral(red: 0.4666666687, green: 0.7647058964, blue: 0.2666666806, alpha: 1)))
                            .shadow(color: Color.primary.opacity(0.5), radius: 20, x: 0, y: 20)
                            .rotation3DEffect(Angle(degrees:10), axis: (x: 10.0, y: 0, z: 0))
                    }
                }
                Spacer()
            }
            .navigationBarBackButtonHidden(true)
            .navigationTitle(appViewModel.userInfo?.company ?? "Test")
            .navigationBarItems(leading: Button(action: {
                appViewModel.signOut()
            }) {
                HStack {
                    Text("Sign Out")
                }
            },trailing: HStack{
                Image(systemName: "bell")
                Text(appViewModel.userInfo?.name ?? "Tester")
                    .font(.system(size: 20))
            })
        }
    }

【问题讨论】:

    标签: firebase google-cloud-firestore swiftui


    【解决方案1】:

    尝试显式隐藏它,比如

    if viewModel.signedIn {
         FirstView()
            .navigationBarHidden(true)    // << here !!
    } else {
    

    【讨论】:

    • 这在我隐藏 LoginView 导航栏时有效,但我仍然想了解它为什么会发生。
    • 因为这是通过视图首选项工作的,所以它是在登录时设置的,但之后不会重置,所以保留在首选项值中。使用显式修饰符会重置首选项,以便更新导航视图。
    【解决方案2】:

    如果您在其他视图中需要它,隐藏导航栏会导致很多问题。我认为更好的答案是

    1 - 创建一个启动视图并将其设置为@main 文件中的起始视图

    2 - 添加一个用于跟踪用户 loginState 的 StateObject :

     class LoginState: ObservableObject {
        @Published var isLogin : Bool = false
    }
    

    3 - 将 navigationView 添加到启动视图

    4 - 将 loginState 、 StateObject 作为 .environmentObject(loginState) 传递给 navigationView

    5- 现在您可以随时随地更改登录状态,而无需隐藏导航栏

    【讨论】:

    • 谢谢 Keyvan,但这就是我已经拥有的,并且工作正常,但现在我想弄清楚的问题是如何在登录时顺利过渡到我的 FirstView 以及新用户登录时如何在我的 FirstView 上更新用户数据。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多