【问题标题】:Slight delay/lag when fetching Firestore User data to update View获取 Firestore 用户数据以更新视图时略有延迟/滞后
【发布时间】:2021-09-05 18:27:34
【问题描述】:

我目前正在构建一个带有登录/注册视图的简单应用,以便更好地了解如何将 SwiftUI 与 Firebase 集成。

我在尝试更新用户数据时遇到了一些问题。我注意到,在以一个用户身份注销然后以其他用户身份登录之后,在点击登录按钮后,在 FirstView 上更新用户信息之前会有一瞬间的延迟。我正在尝试弄清楚如何避免这种延迟的发生。

另一方面,我也无法弄清楚如何从我的 LoginView() 顺利导航到我的 FirstView()。我在 Navigation Stack 中有我的 FirstView(),但是视图之间的转换非常突然并且没有 NavigationLink 动画。我该如何解决这个问题?

非常感谢!

这里是相关代码...

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

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)
                    .navigationBarHidden(true)
            }
        }
        .onAppear {
            viewModel.listen()
        }
    }
}

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 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")
                .font(.system(size: 30))
//            selectedImageArray.first!
//                .resizable()
//                .scaledToFit()
//                .clipShape(Circle())
//                .frame(width: 50, height: 50)
            Text(appViewModel.userInfo?.name ?? "Tester")
                .font(.system(size: 20))
        })
    }
}

【问题讨论】:

  • “我正在想办法避免这种延迟的发生。”我还没有完全阅读您的代码,但我预计延迟来自网络流量(登录调用或从 Firestore 加载数据)。如果是这种情况,则无法摆脱延迟 - 但您当然可以在网络调用完成之前显示加载指示器。
  • 您的第二个问题应该拆分为一个单独的问题,以便可以独立解决。

标签: firebase google-cloud-firestore swiftui


【解决方案1】:

您的导航状态取决于signedIn。在您的身份验证侦听器中,您可以这样做:


DispatchQueue.main.async {
  self.fetchUserData()
}
                
self.signedIn = true

这会将signedIn 设置为true,这将更改您的导航状态,然后在未来不确定的时间,fetchUserData 将完成并更新用户数据(一旦网络调用完成)。

为了避免这种延迟(或者,实际上,只是为了避免在屏幕上看到信息未更新——延迟是网络调用的必然结果),在fetchUserData 完成之前不要设置signedIn。因此,请删除侦听器内的行,并将其设置在您的 self.userInfo = 行之后。

【讨论】:

    猜你喜欢
    • 2022-06-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-10
    • 1970-01-01
    • 2017-02-19
    • 2020-12-31
    相关资源
    最近更新 更多