Search code examples
swiftfunctionswiftuiviewmodelinit

SwiftUI: compiler takes initialized value from ViewModel rather than the value that has been fetched


I'm writing a program where I reference a database where authenticated users each have a document whose ID corresponds to their User ID. Given the user's ID, I am trying to determine their name; I have managed to read all of the user's data and it is in my data model of class Users:

class Users {  
var id: String
var name: String
var surname: String // ...
}

In my ViewModel, I have

@Published var specificUser = User(id: "", name: "", surname: "", email: "", profficiency: 0, lists: [[]])

which is an initialized user. In that same ViewModel, I have a function that fetches the User Data from the database, which appears to work. It should then store the new user data in the specificUserData variable.

 func getData() {
    let db = Firestore.firestore()
    guard let uid = auth.currentUser?.uid else { return }
    db.collection("Users").getDocuments { result, error in
        if error == nil {
            print("Current User's ID found: \(uid)")
            if let result = result {
                // iterate through documents until correct ID is found
                for d in result.documents {
                    if d.documentID == uid {
                        print("Document ID found: \(d.documentID)")
                        self.specificUser = User(
                            id: d.documentID,
                            name: d["name"] as? String ?? "",
                            // ...
                        )
                        print(self.specificUser)
                        print(self.specificUser.name) // This works; my compiler spits out the correct name from the database, so clearly the specificUser variable has been changed. 
                    }
                }
            }
        } else {
            // Handle Error
            print("Error while fetching user's specific data")
        }
    }
}

Here's how I initialized the getData() function:

init() {
    model.getData()
    print("Data Retrieval Complete")
    print("User's Name: \(model.specificUser.name)")
    
}

I am trying to reference my ViewModel like this:

@ObservedObject var model = ViewModel()

Now here's the problem: when I try to reference the User's name from the view model in my struct with

model.specificUser.name

It gives me the default name, even though I have initialized the getData() function already. Checking my compiler log and adding a bunch of print statements, it appears that the initialization is in fact working, but it is printing data retrieval complete before it is printing the albeit correct name.

Any thoughts? It seems that the initializer function is taking the initialized value from my ViewModel rather than the correct value it should be computing.


Solution

  • try this

     func getData(_ completion: @escaping (Bool, User?) -> ()) {
        let db = Firestore.firestore()
        guard let uid = auth.currentUser?.uid else { return }
        db.collection("Users").getDocuments { result, error in
            if error == nil {
                print("Current User's ID found: \(uid)")
                if let result = result {
                    // iterate through documents until correct ID is found
                    for d in result.documents {
                        if d.documentID == uid {
                            print("Document ID found: \(d.documentID)")
                            let user = User(
                                id: d.documentID,
                                name: d["name"] as? String ?? "",
                                // ...
                            )
                            completion(true, user)
                            print(self.specificUser)
                            print(self.specificUser.name) // This works; my compiler spits out the correct name from the database, so clearly the specificUser variable has been changed. 
                        }
                    }
                }
            } else {
                // Handle Error
                completion(false, nil)
                print("Error while fetching user's specific data")
            }
        }
    }
    
    init() {
        model.getData() { res, user in 
        if res { 
           self.specificUser = user! 
        }
        print("Data Retrieval Complete")
        print("User's Name: \(model.specificUser.name)")
    }
        
    }