Displaying Users Data

Hey everyone,

I have been working on a personal project and right now I am struggling to figure out why the user’s data will not display after the app reloads.

When the user first signs in to the app their information is displayed. However, if I close the app and then re-open it, the information is no longer there.

It seems on the reload, the data takes longer to load than the actual view itself. For test purposes, I set up a button that would print a piece of the user’s data to the console, and that worked just fine.

Any idea of how I can go about fixing this?

My code will be found below!

// Launch View
import SwiftUI
import FirebaseAuth

struct LaunchView: View {
    
    @EnvironmentObject var model: UserModel
    
    var body: some View {
        
        if model.loggedIn == false {
            
            // Show LoginView
            LoginView()
                .onAppear {
                    // Check if user is logged in or out
                    self.model.checkLogin()
                }
        }
        else {
            
            // Show ProfileView
            TabView {
                
                ProfileView()
                    .tabItem {
                        VStack {
                            Image(systemName: "person")
                            Text("Profile")
                        }
                    }
                
                Text("Sign Out")
                    .tabItem {
                        VStack {
                            Image(systemName: "rectangle.portrait.and.arrow.right")
                            Text("Sign Out")
                        }
                    }
                    .onAppear {
                        // Sign out the user
                        try! Auth.auth().signOut()
                        
                        // Change to logged out view
                        self.model.checkLogin()
                    }
            }
            .onAppear {
                UITabBar.appearance().backgroundColor = UIColor(red: 248/255, green: 247/255, blue: 248/255, alpha: 100)
            }
        }
    }
}

struct LaunchView_Previews: PreviewProvider {
    static var previews: some View {
        LaunchView()
    }
}
// UserModel

import Foundation
import Firebase
import FirebaseAuth

class UserModel: ObservableObject {
    
    // Authentication
    @Published var loggedIn = false
    
    // Reference to Cloud Firestore database
    private let db = Firestore.firestore()
    
    // MARK: Authentication Methods
    
    func checkLogin() {
        
        // Check if their is a current user to determine login status
        loggedIn = Auth.auth().currentUser != nil ? true : false
        
        // Check if user meta data has been fetched. If the user was already logged in from a previous session, we need to get their data in a seperate call
        if UserService.shared.user.displayName == "" {
            getUserData()
        }
    }
    
    // MARK: Data Methods
    
    func checkUsername(username: String, completion: @escaping (_ userFound: Bool) -> ()) {
        
        // Check for the entered username
        let ref = db.collection("users").whereField("username", isEqualTo: username)
        ref.getDocuments { snapshot, error in
            if let error = error {
                print("Error finding usernames: \(error)")
            }
            else if snapshot!.count > 0 {
                completion(true)
            } else {
                completion(false)
            }
        }
    }
    
    func getUserData() {
        
        // Check that there's a logged in user
        guard Auth.auth().currentUser != nil else {
            return
        }
        
        // Get the meta data for that user
        let ref = db.collection("users").document(Auth.auth().currentUser!.uid)
        
        ref.getDocument { snapshot, error in
            
            // Check there's no errors
            guard error == nil && snapshot != nil else {
                return
            }
            
            // Parse the data out and set the user meta data
            let data = snapshot!.data()
            let user = UserService.shared.user
            user.displayName = data?["displayName"] as? String ?? ""
            user.favouriteTeam = data?["favouriteTeam"] as? String ?? ""
        }
    }
    
    func saveUserData(username: String, favTeam: Int) {
        
        // Save the first name
        let firebaseUser = Auth.auth().currentUser
        let ref = db.collection("users").document(firebaseUser!.uid)
        
        ref.setData(["username":username.lowercased(),
                     "displayName":username,
                     "favouriteTeam": Constants.LCSTeams[favTeam]], merge: true)
        
        // Update the user meta data
        let user = UserService.shared.user
        user.displayName = username
        user.favouriteTeam = Constants.LCSTeams[favTeam]
    }
}

Can you also include the ProfileView?

UserService.shared.user is where you’re saving data but I believe that need to be an environment object that’s injected because if you just try to “use it” on the ProfileView it won’t update cause it’s not “reactive” it’s just a normal variable in memory

And your view won’t update when the network call comes back

I was doing my best to do follow along with what we did in the SwiftUI Firebase Course. I don’t remember making our UserService an environment object. However, I might be doing something where I would need one?

I appreciate you helping me out with this :smiley:

As of right now, I have just hardcoded the username, balance, etc because it wasn’t working and I wanted to continue working on the design while I waited to find a solution. All that is different is that I had user.displayName as the value in the Text element.

//  ProfileView.swift

import SwiftUI
import Firebase

struct ProfileView: View {
    
    @EnvironmentObject var model: UserModel
    @State var user = UserService.shared.user
    
    var body: some View {
        
        GeometryReader { geo in
            VStack (alignment: .leading, spacing: 20) {
                
                Spacer()
                
                // User Info
                HStack {
                    Spacer()
                    Image("lcslogo")
                        .resizable()
                        .scaledToFit()
                        .frame(width: 50)
                    
                    Spacer()
                    
                    VStack(alignment: .leading) {
                        Text("MaseLoL")
                            .font(.headline)
                        Text("Counter Logic Gaming")
                    }
                    
                    Spacer()
                    
                    Button {
                        // TODO: Edit users profile
                        print(UserService.shared.user.displayName)
                    } label: {
                        ZStack {
                            Rectangle()
                                .foregroundColor(.blue)
                                .cornerRadius(10)
                                .frame(width: 110, height: 35)
                            
                            Text("Edit Profile")
                                .foregroundColor(.white)
                        }
                    }
                }
                                
                Text("Hi! My name is MaseLoL, also known as Mase! I am an avid CLG fan for the last 6 year. I main ADC and I am currently Diamond 3 on the NA ladder.")
                                
                // Match History Button
                HStack {
                    Spacer()
                    Button {
                        // TODO: Show match history
                    } label: {
                        ZStack {
                            Rectangle()
                                .foregroundColor(.blue)
                                .cornerRadius(10)
                                .frame(width: 120, height: 40)
                            
                            Text("Match History")
                                .foregroundColor(.white)
                        }
                    }
                }
                                
                // Users Stats
                HStack {
                    ZStack {
                        Rectangle()
                            .foregroundColor(Color(.lightGray))
                            .frame(width: geo.size.width / 3 - 20, height: geo.size.width / 3 - 20)
                        VStack{
                            Text("7")
                                .font(.system(size: 13))
                                .bold()
                            
                            Text("Win Streak")
                                .font(.system(size: 13))
                        }
                    }
                    Spacer()
                    ZStack {
                        Rectangle()
                            .foregroundColor(Color(.lightGray))
                            .frame(width: geo.size.width / 3 - 20, height: geo.size.width / 3 - 20)
                        VStack{
                            Text("25")
                                .font(.system(size: 13))
                                .bold()
                            
                            Text("Correct Games")
                                .font(.system(size: 13))
                        }
                    }
                    Spacer()
                    ZStack {
                        Rectangle()
                            .foregroundColor(Color(.lightGray))
                            .frame(width: geo.size.width / 3 - 20, height: geo.size.width / 3 - 20)
                        VStack{
                            Text("77%")
                                .font(.system(size: 13))
                                .bold()

                            Text("Correct Games %")
                                .font(.system(size: 13))

                        }
                    }
                }
                
                Spacer()
                
                // Users Balance
                ZStack {
                    Rectangle()
                        .foregroundColor(Color(.lightGray))
                        .cornerRadius(10)
                    
                    VStack {
                        Spacer()
                        Text("Current Balance")
                            .font(.system(size: 20))
                            .bold()

                        Spacer()
                        
                        Text("$125.00")
                            .font(.system(size: 40))
                            .bold()
                        
                        Spacer()
                        
                        HStack {
                            Button {
                                // TODO: Withdraw money
                            } label: {
                                ZStack {
                                    Rectangle()
                                        .foregroundColor(.blue)
                                        .cornerRadius(10)
                                        .frame(width: 110, height: 35)
                                    
                                    Text("Withdraw")
                                        .foregroundColor(.white)
                                }
                            }
                            
                            Spacer()
                            
                            Button {
                                // TODO: Deposit money
                            } label: {
                                ZStack {
                                    Rectangle()
                                        .foregroundColor(.blue)
                                        .cornerRadius(10)
                                        .frame(width: 110, height: 35)
                                    
                                    Text("Deposit")
                                        .foregroundColor(.white)
                                }
                            }
                        }
                        .padding(.horizontal, 40)
                        
                        Spacer()
                    }
                }
                
            }
            .padding()
        }
    }
}

struct ProfileView_Previews: PreviewProvider {
    static var previews: some View {
        ProfileView()
    }
}

I tried making UserService an environment object but that gave me the same issues. I have continued working on the project kind of ignoring this bug until I find a solution. I will link my repository to this project that way I don’t have to spam this page with a wall of code.

I appreciate all the help I can get!

Thank you all,

Mason.

Repo: https://github.com/MasonGarrett/swiftui-capstone-project