Grand Central Dispatch 多个 DispatchGroups

Grand Central Dispatch Multiple DispatchGroups

我有三个异步调用。一份 returns 数据,两份 return 图片来自使用 firebase 的 S3。我有一个后台 DispatchQueue 和三个调度组。我需要一种方法让他们同步执行,但他们没有!我什么都试过了,.notify 立即执行,这是错误的。

这个的输出是
图片完成
全部完成
group.notify 完成
getImages() 完成

我想理解的是为什么imagesdone在group.notify完成之前执行?我需要执行第一个组,然后是 imagesGroup,然后是 avaGroup。

我基本上有三个异步调用,第二个/第三个可能是多个异步调用。我如何等待它们完成,然后执行后续调用?

func loadFriendPhotos() {

    let backgroundQueue = DispatchQueue(label: "com.app.queue",
                                        qos: .utility,
                                        target: nil)

    let group = DispatchGroup()
    let imageGroup = DispatchGroup()
    let avaGroup = DispatchGroup()
    typealias tempAlias = (username:String, imageURL: String, pathUrl:String)

    var tempAliasArray = [tempAlias]()
    var imageArray = [UIImage]()
    var avaImageArray = [UIImage]()

    group.enter()
    let workItem = DispatchWorkItem {
        databaseRef.child("friendPhotos").child(globalUsername).observeSingleEvent(of: .value, with: { (snapshot) in
            if snapshot.exists() {

                let enumerator = snapshot.children
                var childrenCount = snapshot.childrenCount


                while let rest = enumerator.nextObject() as? FIRDataSnapshot {

                    let name = rest.childSnapshot(forPath: "username").value as! String
                    let downloadURL = rest.childSnapshot(forPath: "downloadURL").value as! String
                    let uid = rest.childSnapshot(forPath: "uid").value as! String
                    let pathURL = rest.childSnapshot(forPath: "pathURL").value as! String
                    let downloadURLRef = storage.reference(forURL: downloadURL)

                    let newTempAlias = tempAlias(name, downloadURL, pathURL)
                    tempAliasArray.append(newTempAlias)
                }
                group.leave()
            }
        })
    }

    func getAvaImages() {
        for index in tempAliasArray{
            avaGroup.enter()
            let avaItem = DispatchWorkItem {
                let avaURLRef = storage.reference(forURL: index.1)
                avaURLRef.data(withMaxSize: 2 * 1024 * 1024) { (data,error) in
                    if (error == nil) {
                        print("success!")
                        let picData = UIImage(data:data!)
                        avaImageArray.append(picData!)

                    } else {
                        print(error?.localizedDescription)
                    }
                    print("we left getAvaImages()")
                    avaGroup.leave()

                }
            }
            backgroundQueue.async(execute: avaItem)
        }
    }

    func getImages() {
        for index in tempAliasArray{
            imageGroup.enter()
            let imageItem = DispatchWorkItem {
                let downloadURLRef = storage.reference(forURL: index.1)
                downloadURLRef.data(withMaxSize: 2 * 1024 * 1024) { (data,error) in
                    if (error == nil) {
                        let picData = UIImage(data:data!)
                        imageArray.append(picData!)
                    } else {
                        print(error?.localizedDescription)
                    }
                    print("we left getImages()")
                    imageGroup.leave()
                }
            }
            backgroundQueue.async(execute: imageItem)
        }
    }

    backgroundQueue.sync(execute: workItem)

    group.notify(queue: DispatchQueue.main, execute: {
        print("group.notify is done")
        getImages()
    })
    imageGroup.notify(queue: DispatchQueue.main, execute: {
        print("images done")
        getAvaImages()
    })
    avaGroup.notify(queue: DispatchQueue.main, execute: {
        print("all is done")
    })
 }

您在 imageGroup 中没有任何内容时调用 imageGroup.notify,因此它会立即通知。同样,avaGroup 会立即通知,因为在您调用它时它是空的。

但是我不明白所有的间接寻址和分组以及三个数组。为什么在处理每张图片之前必须等待所有图片下载?为什么不直接在原始循环中为一个元素启动下一步呢?像这样:

var allTheResults = []

group.enter() // Enter once for the top-level
kickOffAsyncWithCompletion { resultList in

    for item in resultList {
        let resultThing = doSomeStuffToSetupNextLevel()

        group.enter() // Enter once per thing we iterate over

        kickOffNestedAsync(with: resultThing, completion: { result in
            let finalResult = computeFinalResult(fromResult: result)
            allTheResults.append(finalResult)
            group.leave() // leave once per thing we iterate over
        })
    }
    group.leave() // leave once for the top level
}

group.notify { doThing(withFinalResults: allTheResults) }

如果您想协调一组操作的端点,您希望所有这些操作都与同一个组一起工作,而不是每个操作单独的组。