How to track Current user data

I want to track CURRENT USER data (that I previously saved into firebase) as those are my inputs/preferences for multiple firebase fetches.

I used a UserService (aka SINGLETON) as shown by Chris in the learning app lesson, then get data from firebase, put it into a user() instance…but the data is not being saved across views…basically I want it to persist across views

current_user data saved-> fetch into a user()-> use it for many comparisons or queries to firebase

Is there another way to track CURRENT USER data while the app it’s in use?

I read about UserDefaults somewhere but I wanted to ask here as well what’s the right way to do it.
ps: I was also thinking to host the current_user data as published properties ion the content model

thanks

Nat

USER SERVICE

import Foundation

class UserService {
    
    var user = User()
    
    static var shared = UserService()
    
    private init() {
        
    }
}

LAUNCH LOGIC

import SwiftUI

struct LaunchLogicView: View {
    
    @AppStorage("isOnboarding") var isOnboarding: Bool?
    //@AppStorage("onboardingScreen") var onboardingScreen: String?
    
    @EnvironmentObject var model: ContentModel //because we depend on content model to know if user is loggedin (loggedin property)
    let persistenceController = PersistenceController.shared
    
    var body: some View {
        
        if model.loggedIn == false {
            WelcomeScreenView()
                .onAppear() {
                    model.checkLogin()
                }
        }
        else {
            if isOnboarding == true {
                BirthOnboardingView(index: 2)
                    .onAppear() {
                        model.checkLogin()
                    }
            }
            else {
                //TabView
                TabView {
                    MatchView(index: 0)
                        .tabItem {
                            VStack {
                                Image(systemName: "heart")
                                Text("Match")
                            }
                        }
                    
                    ChatView()
                        .tabItem {
                            VStack {
                                Image(systemName: "bubble.left.and.bubble.right.fill")
                                Text("Chat")
                            }
                        }
                    
                    ProfileView()
                        .tabItem {
                            VStack {
                                Image(systemName: "person")
                                Text("Profile")
                            }
                        }
                }
                .onAppear {
                    model.getMatches()
                }
            }
        }

checkLOGIN and FETCH USER DATA into userService

func checkLogin() {
        //to check if user is logged in or not every time the app opens
        loggedIn = Auth.auth().currentUser != nil ? true : false
        //if current user is nil then loggedin = false
        
        //CHECK IF USERR metadata has been FETCHED. if the user was already logged in from a previous session, we need to get their data in a separate call
        if UserService.shared.user.name == "" { 
            getUserData() //to fetch metadata related to user
        }
    }
    
    //retrieve user data for the first time
    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 db = Firestore.firestore()
        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.name = data?["name"] as? String ?? ""
            user.birthdate = data?["birthdate"] as? Date ?? Date()
            user.gender = data?["gender"] as? String ?? ""
            user.height = data?["height"] as? Int ?? 0
            user.latitude = data?["latitude"] as? Double ?? 0.0
            user.longitude = data?["longitude"] as? Double ?? 0.0
            user.datingPreferences = data?["datingPreferences"] as? String ?? ""
            user.sexuality = data?["sexuality"] as? String ?? ""
            
            user.Q1day2live = data?["Q1day2live"] as? String ?? ""
            user.QlotteryWin = data?["QlotteryWin"] as? String ?? ""
            user.QmoneynotanIssue = data?["QmoneynotanIssue"] as? String ?? ""
            user.bucketList = data?["bucketList"] as? String ?? ""
            user.jokes = data?["jokes"] as? String ?? ""

        }
    }
    
    func getMatches() {
    

        // Get the documents from the collection
        let usersCollection = db.collection("users")
        
        //if user wants to date FEMALE
        let user = UserService.shared.user
        if user.datingPreferences == "Female" {
            let query = usersCollection
                .whereField("gender", in: ["Female"])
                .whereField("datingPreferences", in: [user.datingPreferences, "Everyone"])
            
            query.getDocuments { snapshot, error in
                if error == nil {
                    
                    var usuarios = [User]() //empty array of user instances
                    
                    for doc in snapshot!.documents {
                        
                        var u = User()
                        //q.id = doc["id"] as? String ?? ""
                        u.name = doc["name"] as? String ?? ""
                        u.birthdate = doc["birthdate"] as? Date ?? Date()
                        u.gender = doc["gender"] as? String ?? ""
                        u.height = doc["height"] as? Int ?? 0
                        u.latitude = doc["latitude"] as? Double ?? 0.0
                        u.longitude = doc["longitude"] as? Double ?? 0.0
                        
                        u.Q1day2live = doc["Q1day2live"] as? String ?? ""
                        u.QlotteryWin = doc["QlotteryWin"] as? String ?? ""
                        u.QmoneynotanIssue = doc["QmoneynotanIssue"] as? String ?? ""
                        u.bucketList = doc["bucketList"] as? String ?? ""
                        u.jokes = doc["jokes"] as? String ?? ""
                        
                        usuarios.append(u)
                    }
                    
                    DispatchQueue.main.async {
                        self.users = usuarios
                        self.usersLoaded = true
                    }
                }
        }
        
        }
        
        //if user wants to date MALE
        if user.datingPreferences == "Male" {
            let query = usersCollection
                .whereField("gender", in: ["Male"])
                .whereField("datingPreferences", in: [user.datingPreferences, "Everyone"])
            
            query.getDocuments { snapshot, error in
                if error == nil {
                    
                    var usuarios = [User]() //empty array of user instances
                    
                    for doc in snapshot!.documents {
                        
                        var u = User()
                        //q.id = doc["id"] as? String ?? ""
                        u.name = doc["name"] as? String ?? ""
                        u.birthdate = doc["birthdate"] as? Date ?? Date()
                        u.gender = doc["gender"] as? String ?? ""
                        u.height = doc["height"] as? Int ?? 0
                        u.latitude = doc["latitude"] as? Double ?? 0.0
                        u.longitude = doc["longitude"] as? Double ?? 0.0
                        
                        u.Q1day2live = doc["Q1day2live"] as? String ?? ""
                        u.QlotteryWin = doc["QlotteryWin"] as? String ?? ""
                        u.QmoneynotanIssue = doc["QmoneynotanIssue"] as? String ?? ""
                        u.bucketList = doc["bucketList"] as? String ?? ""
                        u.jokes = doc["jokes"] as? String ?? ""
                        
                        usuarios.append(u)
                    }
                    
                    DispatchQueue.main.async {
                        self.users = usuarios
                        self.usersLoaded = true
                    }
                }
        }
        
        }
        

You could save the data to user defaults!

Or because you’re using a more complicated thing to save (more than just a Boolean) you can try using Core Data

UserDefaults is really only meant to save small bits of data.

This is also for saving through different sessions. Meaning, open the app, close it and open it again, you’d use UserDefaults/CoreData to persist the data through those different sessions of the app.

If you just want to save data from one view controller (Swift view) to the next you should pass the data from one to the next

thank you, I’ll use core data for this.

I was also able to make the singleton work. I realized the firebase calls are async and sometimes I was making a comparison BEFORE the userService received the data back from Firestore. I read about completion but I did not fully understand. any best practices to make sure we execute step 2 once we fetch all firebase data? (now I’m using published booleans)

In this code block is when you have data returned from Firebase because yes it’s asynchronous. That’s when you can now add a function in here somewhere that does your comparison.