Как дождаться завершения обработки изображений перед перезагрузкой данных представления коллекции?

#ios #swift

#iOS #swift

Вопрос:

Я использую новый API-интерфейс выбора изображений в iOS 14 и хотел бы иметь возможность завершить обработку изображений в цикле for перед вызовом моего кода внизу, который обновляет мои источники данных, а затем, наконец, перезагружает данные представления коллекции. В настоящее время код внизу вызывается до того, как значение totalConversionsCompleted достигнет 1.

 func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {

    dismiss(animated: true, completion: nil)

    var selectedImageDatas = [Data?](repeating: nil, count: results.count) // Awkwardly named, sure
    var totalConversionsCompleted = 0

    for (index, result) in results.enumerated() {
        result.itemProvider.loadFileRepresentation(forTypeIdentifier: UTType.image.identifier) { (url, error) in
            guard let url = url else {
                totalConversionsCompleted  = 1
                return
            }

            let sourceOptions = [kCGImageSourceShouldCache: false] as CFDictionary

            guard let source = CGImageSourceCreateWithURL(url as CFURL, sourceOptions) else {
                totalConversionsCompleted  = 1
                return
            }

            let downsampleOptions = [
                kCGImageSourceCreateThumbnailFromImageAlways: true,
                kCGImageSourceCreateThumbnailWithTransform: true,
                kCGImageSourceThumbnailMaxPixelSize: 2_000,
            ] as CFDictionary

            guard let cgImage = CGImageSourceCreateThumbnailAtIndex(source, 0, downsampleOptions) else {
                totalConversionsCompleted  = 1
                return
            }

            let data = NSMutableData()

            guard let imageDestination = CGImageDestinationCreateWithData(data, kUTTypeJPEG, 1, nil) else {
                totalConversionsCompleted  = 1
                return
            }

            // Don't compress PNGs, they're too pretty
            let isPNG: Bool = {
                guard let utType = cgImage.utType else { return false }
                return (utType as String) == UTType.png.identifier
            }()

            let destinationProperties = [
                kCGImageDestinationLossyCompressionQuality: isPNG ? 1.0 : 0.75
            ] as CFDictionary

            CGImageDestinationAddImage(imageDestination, cgImage, destinationProperties)
            CGImageDestinationFinalize(imageDestination)

            selectedImageDatas[index] = data as Data
            totalConversionsCompleted  = 1
        }
    }


    //I want to wait for the processing of images and then do this

    self.images.append(contentsOf: selectedImageDatas)

    RxBus.shared.post(event: Events.AlbumUpdated(images: self.images, indexPath: self.selectedIndexPath))

    self.collectionView.reloadData()

}
  

Комментарии:

1. Я бы посоветовал DispatchGroup.

2. Где я мог бы вызвать leave(), как если бы я вызывал его после того, как я увеличил totalConversionsCompleted , код внизу, который я помещаю в блок wait:, вызывается несколько раз

Ответ №1:

     let g = DispatchGroup()
    for (index, result) in results.enumerated() {
        g.enter()
        result.itemProvider.loadFileRepresentation(forTypeIdentifier: UTType.image.identifier) { (url, error) in
            ...
            g.leave()
        }
    }
    g.notify(queue: .main) {
        // completed here
    }