I'm getting confused with nested async calls in Swift using Firebase Firestore. I'm trying to make a friends page for my app, and part of the page is a UITableView of groups of the users' friends. I'm storing these groups within a separate collection in Firebase, and attempting to get a list of the groups the current user is in from the document IDs in the group collection. Right now, that looks like this:
func createGroupsArray(completion: @escaping ([Group]?) -> Void) {
let dispatchGroup1 = DispatchGroup()
let dispatchGroup2 = DispatchGroup()
var groups = [Group]()
let currentUser = User.current
guard currentUser.groupDocStrings.count > 0 else {
return completion(nil)
}
for g in currentUser.groupDocStrings {
dispatchGroup1.enter()
FirestoreService.db.collection(Constants.Firestore.Collections.groups).document(g).getDocument { (snapshot, err) in
if let err = err {
print("Error retrieving group document: \(err)")
return completion(nil)
} else {
let data = snapshot?.data()
var friends = [User]()
for f in data![Constants.Firestore.Keys.users] as! [String] {
dispatchGroup2.enter()
FirestoreService.db.collection(Constants.Firestore.Collections.users).document(f).getDocument { (snapshot, err) in
if let err = err {
print("Error retrieving user document: \(err)")
return completion(nil)
} else {
let uData = snapshot?.data()
friends.append(User(uid: f, data: uData!))
}
dispatchGroup2.leave()
}
}
dispatchGroup2.notify(queue: .main) {
let group = Group(groupName: data![Constants.Firestore.Keys.groupName] as! String, friends: friends)
groups.append(group)
}
dispatchGroup1.leave()
}
}
}
dispatchGroup1.notify(queue: .main) {
completion(groups)
}
}
But of course, when I go to call this function in my tableView(cellForRowAt) function, I can't return a cell because it's asynchronous. I feel like there must be a better way to do this, any help?