#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
}