I'm having trouble because I am loading a very big number of data entries (about 1000) in the form of users. Now, I fetch the users userIDs and insert their rows with the user data into my table view. The thing is, that currently my app waits until it has finished going through all the userIDs there are and only then starts inserting them. Here's the code:
let group = DispatchGroup()
for each in userIDs {
check(identifier: "DispatchGroup", text: "\(each) started")
Database.database().reference().child("user-data").child(each).observeSingleEvent(of: .value, with: { (snap) in
if let data = snap.value as? [String:AnyObject] {
if let name = data["name"] as? String, let urlToImage = data["imagePath"] as? String, let status = data["status"] as? String {
let newUser = User()
newUser.name = name
newUser.imagePath = urlToImage
newUser.status = status
self.usersTableView.append()
if let index = self.usersTableView.index(of: newUser) {
self.tableView.insertItems(at: [IndexPath(row: index, section: 0)])
check(identifier: "FeedLoad", text: "inserting user \(newUser.userName) at timestamp \(Date().timeIntervalSince1970)")
}
check(identifier: "DispatchGroup", text: "\(each) ended")
print("Reloading table view at \(Date().timeIntervalSince1970)")
group.leave()
}
}
})
}
Now, what that prints me out is this:
DispatchGroup: xRDlUIBAsqeI13ykVsEx9P7okph2 started
DispatchGroup: dFVZAQmPb0TRRD94sPR32FbYWyk1 started
DispatchGroup: xRDlUIBAsqeI13ykVsEx9P7okph2 ended
DispatchGroup: dFVZAQmPb0TRRD94sPR32FbYWyk1 ended
But I want it to say:
DispatchGroup: xRDlUIBAsqeI13ykVsEx9P7okph2 started
DispatchGroup: xRDlUIBAsqeI13ykVsEx9P7okph2 ended
DispatchGroup: dFVZAQmPb0TRRD94sPR32FbYWyk1 started
DispatchGroup: dFVZAQmPb0TRRD94sPR32FbYWyk1 ended
How do I achieve this?
There are a couple of ways to achieve this. Firebase has no completion handlers for that sort of stuff, but what you could do is if you have a small amount of IDs in for loop just do is nest it like this:
Database.database().reference().child("user-data").child(id1).observeSingleEvent(of: .value, with: { (snap) in
Database.database().reference().child("user-data").child(id2).observeSingleEvent(of: .value, with: { (snap) in
Database.database().reference().child("user-data").child(id3).observeSingleEvent(of: .value, with: { (snap) in
}
}
}
But if that data can vary, the other way of achieving this would be to store a dictionary of ids and Bool to check if finished.
var ids = ["id1" : false, "id2" : false, "id3" : false]
func getNext() {
// If all ids == true { return }
// if not, get the next id
Database.database().reference().child("user-data").child(id1).observeSingleEvent(of: .value, with: { (snap) in
ids["id1"] = true
getNext()
}
}
And also don't call Database.Database().reference()
every request. Instead store it as a variable. Check this for more info : Firebase best practices