如何使用带有两个循环的DispatchGroup

时间:2017-09-02 18:38:18

标签: swift grand-central-dispatch

我目前有一个数组,它迭代了值图像路径,并希望在第一个中的for循环中异步检索这些图像。我尝试过使用两个调度组,但总是在检索图像之前返回完成处理程序。

static func getAllEntriesWithDisplayModel(completion: @escaping (_ models: [EntryDisplayModel]) -> ()) -> (){
        let entries = Array(realm.objects(Entry.self)).reversed()
        var displayModels: [EntryDisplayModel] = []

    let options = PHFetchOptions()
    let entriesGroup = DispatchGroup()

    entries.forEach{

        entriesGroup.enter()
        var model = EntryDisplayModel(entry: $0)

        let paths: [String] = $0.imagePaths.flatMap{en in
            en.path
        }
        let assets = PHAsset.fetchAssets(withLocalIdentifiers: paths, options: options)
        assets.enumerateObjects({ (object, count, stop) in
            model.assets?.append(object)
        })

        let assetsGroup = DispatchGroup()

        let requestOptions = PHImageRequestOptions()
        requestOptions.resizeMode = PHImageRequestOptionsResizeMode.exact
        requestOptions.deliveryMode = PHImageRequestOptionsDeliveryMode.highQualityFormat
        requestOptions.isSynchronous = true

        var images: [UIImage]? = []

        model.assets?.forEach{
            assetsGroup.enter()

            // Fetch images using local paths from images save
            PHImageManager.default().requestImage(for: $0, targetSize: PHImageManagerMaximumSize, contentMode: PHImageContentMode.default, options: requestOptions, resultHandler: { (image, info) in
                guard let img = image else {
                    assetsGroup.leave()
                    return
                }
                images?.append(img)
                assetsGroup.leave()
            })
        }
        assetsGroup.notify(queue: .main, execute: {
            model.images = images
            print("FETCHED \(images?.count ?? 0) IMAGES")
            print("DISPLAY MODEL CREATED ")
            displayModels.append(model)
        })

    }
   entriesGroup.leave()
    //Returns too early
    entriesGroup.notify(queue: .main, execute: {
        print(" FINISHED CREATING DISPLAY MODELS")
        completion(displayModels)
    })
}

1 个答案:

答案 0 :(得分:2)

似乎您的代码调用过早entriesGroup.leave()。您知道,您的assetsGroup.leave()在完成处理程序中被调用,而不是在forEach循环结束后立即调用:

static func getAllEntriesWithDisplayModel(completion: @escaping (_ models: [EntryDisplayModel]) -> ()) -> (){
    //...

    entries.forEach{

        entriesGroup.enter()

        //...

        let assetsGroup = DispatchGroup()

        //...

        model.assets?.forEach {_ in
            assetsGroup.enter()

            // Fetch images using local paths from images save
            PHImageManager.default().requestImage(for: $0, targetSize: PHImageManagerMaximumSize, contentMode: PHImageContentMode.default, options: requestOptions, resultHandler: { (image, info) in
                //...
                assetsGroup.leave()
            }
        }
        assetsGroup.notify(queue: .main, execute: {
            model.images = images
            print("FETCHED \(images?.count ?? 0) IMAGES")
            print("DISPLAY MODEL CREATED ")
            displayModels.append(model)
            entriesGroup.leave() //<-`entriesGroup.leave()` needs to be called after all processing for the entry is finished.
        })

    }
    //entriesGroup.leave() //<-It is too early to call `entriesGroup.leave()` here
    entriesGroup.notify(queue: .main, execute: {
        print(" FINISHED CREATING DISPLAY MODELS")
        completion(displayModels)
    })
}