Swift - 循环中的完成处理程序

时间:2018-05-08 15:52:14

标签: ios swift

我有一个带有完成处理程序的方法

func postLandGradingImages(cellHolder: Array<ImagesData>, completionHandler:@escaping (_ result:Bool) -> Void) {

        //Define bool for returning data

        var returnedResults = false

        //Call API

        WebService().postLandGradingImages(cellHolder)
        {
            (result: Bool) in

            DispatchQueue.main.async {

                //Return our results

                returnedResults = result
                completionHandler(returnedResults)

            }

        }

    }

我在循环中调用此方法,如下所示:

for asset: PHAsset in photoAssets
{
    self.postLandGradingImages(cellHolder: [ImagesData(jobNo: self.JobNo, ImageBytes: imageStr)]) { result in

    }
}

我想要做的是,如果在某些时候失败,显示警告并停止循环,循环完成后我的所有调用返回true,最后显示警告。

这就是我的尝试:

var returned = false

        for asset: PHAsset in photoAssets
        {
            imageManager.requestImage(for: asset, targetSize: CGSize(width: asset.pixelWidth, height: asset.pixelHeight), contentMode: .aspectFill, options: options, resultHandler: { (image, info) in

                let imageData:Data = UIImagePNGRepresentation(image!)!

                let imageStr = imageData.base64EncodedString()

                self.postLandGradingImages(cellHolder: [ImagesData(jobNo: self.JobNo, ImageBytes: imageStr)]) { result in

                    returned = result

                    if(returned == false)
                    {
                        self.customAlert(title: "Error", message: "There was an error when saving data, please try again later.")
                    }

                }

            })
        }

        if(returned == true)
        {
            self.customAlert(title: "Error", message: “All Good“)
        }

但是我的警告说All Good永远不会出现,因为在我第一次打电话之前,他们会被检查。我做错了什么,我如何完成我想要完成的任务?

1 个答案:

答案 0 :(得分:2)

问题是你的for循环会很快完成。实际上,正如您所见,循环将在完成一个完成块之前完成。这是异步处理的本质。

通过使用DispatchGroup,您可以设置代码,这样只有在所有完成块完成后,它才会执行代码块,无论循环本身完成的速度有多快。

另请注意,循环内部有两级异步调用。

以下是设置代码的方法。另请注意,我修复了其他几个问题,例如强制解包。

var returned = true // assume success for all

let group = DispatchGroup()

for asset in photoAssets {
    group.enter() // for imageManager
    imageManager.requestImage(for: asset, targetSize: CGSize(width: asset.pixelWidth, height: asset.pixelHeight), contentMode: .aspectFill, options: options, resultHandler: { (image, info) in
        if let image = image, let let imageData = UIImagePNGRepresentation(image) {
            let imageStr = imageData.base64EncodedString()

            group.enter()
            self.postLandGradingImages(cellHolder: [ImagesData(jobNo: self.JobNo, ImageBytes: imageStr)]) { result in
                if !result {
                    returned = false // we had a failure
                }
                group.leave()
            }
        }
        group.leave() // imageManager
    })
}

group.notify(queue: DispatchQueue.main) {
    if returned {
        self.customAlert(title: "Success", message: “All Good“)
    } else {
        self.customAlert(title: "Error", message: "There was an error when saving data, please try again later.")
    }
}

完成所有这些后,您需要更新postLandGradingImages。没有必要将主队列用于完成处理程序。

func postLandGradingImages(cellHolder: Array<ImagesData>, completionHandler:@escaping (_ result:Bool) -> Void) {
    //Call API
    WebService().postLandGradingImages(cellHolder) { (result: Bool) in
        //Return our results
        completionHandler(result)
    }
}