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
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()
}
}