1

When a user first logs into their profile, I retrieve there user name and profile picture. My issue is the site loads and firebase takes around a second to load the information. For example, there username will flash "unavailable" for a brief moment, before displaying the name.

Would love to get feedback on how to better improve my process of retrieving the information. Thank you! For the sake of less code, I didn't include my profile picture logic, as I'm guessing my issue has to do with the way I'm calling Firebase in the first place in my dashboard logic class.

struct UserDashController: View {
    @ObservedObject var vm = DashboardLogic()
  
    @State private var action: Int? = 0
    @State private var userSigningOut = false
    @State private var showMenu = false
    @State private var presentSettingsPage = false
   
    var body: some View {
        NavigationView{
            VStack{
                HStack{
//retrieve username
                    Text(vm.userModel?.name ?? "Name Unavailable" )
                }
                    .padding()
                   
                }
                .padding(.top, -5)
        
            }
         } 

Dashboard Logic

class DashboardLogic: ObservableObject {
    @Published var userModel: UserModel?
    @Published var privateUserModel: privateUserModel?
    
    init(){
        fetchCurrentUser()
    }

    private func fetchCurrentUser () {
        guard let uid = FirebaseManager.shared.auth.currentUser?.uid else {
            return
        }
        guard let email = FirebaseManager.shared.auth.currentUser?.email else {
            print("could not locate email")
            return
        }
        
        FirebaseManager.shared.firestore
            .collection("users").document(uid)
            .getDocument { snapshot, error in
                if let error = error {
                    print ("failed to fetch user \(error)")
                    return
                }
            
            guard let data = snapshot?.data() else {
                print ("no data found for user")
                return
            }

                self.userModel = .init(data: data)
        }
        //save to private database
        FirebaseManager.shared.firestore
            .collection("users").document(uid)
            .collection("privateUserInfo")
            .document("private")
            .getDocument { snapshot, error in
                if let error = error {
                    print("oh no we messed up")
                    return
                }
                //save snapshot of database from firestore
                guard let userEmail = snapshot?.data() else {
                    print("no email found for user")
                    return
                }
                
                self.privateUserModel = .init(data:userEmail )
            }
        
    }
}

USER MODEL

struct UserModel {
    var uid, name, gender, height, weight, agenda, profilePictureURL: String
    
    init(data: [String: Any]){
        self.uid = data["uid"] as? String ?? "Unavailable"
        self.name = data["name"] as? String ?? "Unavailable"
        self.gender = data["gender"] as? String ?? "Unavailable"
        self.height = data["height"] as? String ?? "Unavailable"
        self.weight = data["weight"] as? String ?? "Unavailable"
        self.agenda = data["agenda"] as? String ?? "Unavailable"
        self.profilePictureURL = data ["profilePicture"] as? String ?? "Unavailable"
    }
}

struct privateUserModel {
    var email: String
    
    init(data: [String: Any]){
        self.email = data["email"] as? String ?? "Unavailable"
    }
}
Swink
  • 353
  • 3
  • 26

2 Answers2

0

The only I would change is to update published properties on main queue, like

DispatchQueue.main.async {
  self.userModel = .init(data: data)
}

// ...

DispatchQueue.main.async {
  self.privateUserModel = .init(data:userEmail )
}

everything else I assume is just network delays.

Asperi
  • 228,894
  • 20
  • 464
  • 690
0

Update

It’s not predictable for how long the latency will last, but you could implement loading animation features while waiting for the data to be fetched from Cloud Firestore instead of having just a simple “Unavailable” message, like in this post.

There are also some ways to handle loading states within SwiftUI views as described here, from self-loading views, view models to connecting Combine publishers to views and supporting custom loading views.

On the other hand, you could use an activity indicator and try a view called ProgressView as described in this other post.

As a complement and from a Cloud Firestore configuration perspective, you can improve your process of retrieving data following the best practices such as selecting the database location closest to your users and compute resources. Far-reaching network hops are more error-prone and increase query latency.

You can also follow these practices about the use of asynchronous methods that can reduce your delays as completion handlers or using async/await.

Finally, consider that the delay can be generated for external conditions in the network itself.

You may also be interested in looking into this other related question.

Osvaldo
  • 473
  • 1
  • 12