Home > Software design >  I have a completionHandler for my database query, but now what?
I have a completionHandler for my database query, but now what?

Time:06-18

So I managed to create a database handler class that has a function to retrieve user data from firestore:

    func getArtistProfileCardData(artistName: String, completionHandler: @escaping (UserModel) -> ()){
        
        let usersRef = db.collection("users")
        usersRef.whereField("artistName", isEqualTo: artistName)
            .getDocuments { (querySnapshot, err) in
                if let err = err {
                            print("Error getting documents: \(err)")
                        } else {
                            for document in querySnapshot!.documents {
                                print("\(document.documentID) => \(document.data())")
                                do {
                                    let userData = try document.data(as: UserModel.self)
                                    completionHandler(userData)
                                    // printing retData.artistName gives me correct output.
                                } catch _ {
                                    print("Error getting document from querySnapshot.")
                                }
                            }
                        }
            }
        }

I recently learned how to use completion handlers to return this data out of the DBHandler method. But, how do I go about using it for my SwiftUI views? The data is still inside a closure now like this:

struct ArtistProfileCard: View {
    @State var user: UserModel
    
    let dbhandler = DBHandler() 
    dbhandler.getArtistProfileCardData(artistName: "something") { userData in
        // stuff to do with userDAta
    }
        
    var body: some View {
        VStack(alignment: .leading) {
            Spacer()
            Text(user.artistName ?? "??")
                .font(.title)
                .bold()
                .textCase(.uppercase)
            Text(user.occupation)
            Text("\(user.followers) Followers")
        }

// and the code continues like for any typical UI view... 

and I don't know how to extract it out to put it in my View. Am I going about handling my database incorrectly? Should I completely change the approach to DB management in my App?

Here are some errors thrown when I try and run the code as above

Some errors

CodePudding user response:

This is SwiftUI. You don't need a completion handler.

Declare DBHandler as class conforming to ObservableObject and userData as @Published property.

Side note: userData should be non-optional by adding a static property to UserModel with example data. And you should also handle the error

class DBHandler : ObservableObject {

    @Published var userData: UserModel?
    // better: @Published var userData = UserModel.example

    init() {
       getArtistProfileCardData(artistName: "something")
    }

    func getArtistProfileCardData(artistName: String){
        
        let usersRef = db.collection("users")
        usersRef.whereField("artistName", isEqualTo: artistName)
            .getDocuments { (querySnapshot, err) in
                if let err = err {
                            print("Error getting documents: \(err)")
                        } else {
                            for document in querySnapshot!.documents {
                                print("\(document.documentID) => \(document.data())")
                                do {
                                    let userData = try document.data(as: UserModel.self)
                                    DispatchQueue.main.async {
                                        self.userData = userData
                                    }
                                    
                                } catch {
                                    print("Error getting document from querySnapshot.", error)
                                }
                            }
                        }
            }
        }

}

And in the view create an instance of DBHandler as @StateObject

struct ArtistProfileCard: View {
    @StateObject var dbhandler = DBHandler() 
   
    var body: some View {
        VStack(alignment: .leading) {
            if let user = dbhandler.userData {
                Spacer()
                Text(user.artistName ?? "??")
                    .font(.title)
                    .bold()
                    .textCase(.uppercase)
                Text(user.occupation)
                Text("\(user.followers) Followers")
            } else {
                EmptyView()
            }
        }
  • Related