代码之家  ›  专栏  ›  技术社区  ›  trndjc

使用DispatchGroup在for-in循环中处理异步回调仅在所有循环成功时有效

  •  1
  • trndjc  · 技术社区  · 6 年前

    下面的代码是该任务的概要。查询数据库时,它返回一个结果集合,该集合在搜索特定属性时循环,如果找到该属性,则立即查询文件存储,其异步完成处理程序在循环中返回文件。因为我在for-in循环中处理异步回调,所以我使用 DispatchGroup someIdentifier 财产。如果集合中的一个文档没有该属性,则分派组从不调用 notify()

    someDatabaseQuery.retrieveSomeData { (data, error) in
    
        guard let data = data, error == nil else {
            return
        }
    
        // database has retrieved data, create dispatch group
        let dispatchGroup = DispatchGroup()
    
        for document in data { // loop through collection
    
            // check if document has some identifier
            guard let someIdentifier = document["someIdentifier"] as? String else {
                return
            }
    
            dispatchGroup.enter() // identifier found, enter dispatch
    
            // perform async operation inside loop
            Filestorage.getSomeFile(forURL: someIdentifier) { (data, error) in
    
                guard let file = data, error == nil else {
                    return
                }
    
                // download the file
                dispatchGroup.leave() // leave dispatch
    
            }
    
        }
    
        dispatchGroup.notify(queue: .main) {
    
            // all data grabbed, load table
    
        }
    
    }
    
    2 回复  |  直到 6 年前
        1
  •  3
  •   rmaddy    6 年前

    你必须打电话 leave enter . 但是 guard getSomeFile 完成块可以阻止对的调用 离开 .

    defer 在完成区块内。呼叫 内部 以确保无论您如何离开该区块,都会调用它。

        2
  •  0
  •   Samuel Liew cicero lopes    6 年前
    guard let someIdentifier = document["someIdentifier"] as? String else {
        continue // this is the proper control flow statement
    }
    

    问题只是选择了错误的控制流语句。当防护装置在回路内失灵时, return 阻止循环完成,并且从未给调度组通知的机会。警卫中的else条款应该是 continue ,将控制权保留在循环内(通过让它完成),从而使调度组有机会通知。