Nested Dispatch Groups Swift

流过昼夜 提交于 2019-12-06 00:46:39

问题


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.


回答1:


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.



来源:https://stackoverflow.com/questions/41945991/nested-dispatch-groups-swift

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!