When a user creates a new group in my app I have to push invites to the database as well as other information. I've started using Dispatch Groups in order to keep track of when all the information is successfully sent out so I can dismiss the view.
I'm trying to use a dispatch group for the invites and another dispatch group for all the data. Here's what I have:
// Push new data to db
func createGroup(onSccess completion:@escaping () -> Void) {
let inviteDispatchGroup = DispatchGroup()
let dataDispatchGroup = DispatchGroup()
let uid = FIRAuth.auth()?.currentUser?.uid
let name = String(uid!) + "_" + nameTextField.text!
// push invites
dataDispatchGroup.enter()
for invite in invites {
inviteDispatchGroup.enter()
let ref = FIRDatabase.database().reference().child("users").child(invite.id).child("invites")
ref.updateChildValues([name: nameTextField.text!]) { (error, ref) -> Void in
inviteDispatchGroup.leave()
}
}
inviteDispatchGroup.notify(queue: DispatchQueue.main, execute: {
dataDispatchGroup.leave()
})
// store picture
dataDispatchGroup.enter()
let storageRef = FIRStorage.storage().reference().child("profile_images").child("\(name).png")
if let uploadData = UIImagePNGRepresentation(profImage.resizeImage(targetSize: CGSize(width: 500, height: Int(500*(profImage.size.height/profImage.size.width))))) {
storageRef.put(uploadData, metadata: nil, completion: { (metadata, error) in
dataDispatchGroup.leave()
})
}
// store pet info
dataDispatchGroup.enter()
let petRef = FIRDatabase.database().reference().child("pets").child(name)
petRef.setValue(["mod":uid!, "name":nameTextField.text!, "members":[uid!]]) { (error, ref) -> Void in
dataDispatchGroup.leave()
}
// store user info
dataDispatchGroup.enter()
let userRef = FIRDatabase.database().reference().child("users").child(uid!).child("pets")
userRef.updateChildValues([name: true]) { (error, ref) -> Void in
dataDispatchGroup.leave()
}
dataDispatchGroup.notify(queue: DispatchQueue.main, execute: {
completion()
})
}
As you can see, when the invitesDipatchGroup
is completed it's corresponding dataDispatchGroup
is left.
I'm new to Dispatch groups and want to hear if this is the correct approach to be taking with this sort of task.
This is a very good approach for async task tracking.
It is important to check if all code paths are covered with leave()
. You have a potential bug, if the if let
doesn't have the value not optional. Fixed here:
func createGroup(onSccess completion:@escaping () -> Void) {
[...]
// store picture
dataDispatchGroup.enter()
let storageRef = FIRStorage.storage().reference().child("profile_images").child("\(name).png")
if let uploadData = UIImagePNGRepresentation(profImage.resizeImage(targetSize: CGSize(width: 500, height: Int(500*(profImage.size.height/profImage.size.width))))) {
storageRef.put(uploadData, metadata: nil, completion: { (metadata, error) in
dataDispatchGroup.leave()
})
} else {
dataDispatchGroup.leave()
}
[...]
}
In general always also make sure that all completion blocks are called in all of the code paths of methods you use. There always may be a bug in Firebase or there may be something about the completion not being called in the documentation of those methods. But again, this is the way to go.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With