iOS 14: PHPickerViewController есть ли способ загрузить все активы одновременно? PHPickerResult
В настоящее время я пытаюсь погрузиться в PHPickerViewController для одновременного выбора нескольких изображений из фотографий. поэтому я хочу массив изображений, выбранных пользователем, я пробовал слишком много способов, но не повезло. Это мой код, скажите, пожалуйста, есть ли лучший способ сделать это?
func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
picker.dismiss(animated: true, completion: nil)
var images: [UIImage?] = []
var totalConversionsCompleted = 0
for (index,result) in results.enumerated() {
result.itemProvider.loadObject(ofClass: UIImage.self, completionHandler: { (object, error) in
let image = object as? UIImage
images.append(image)
totalConversionsCompleted += 1
if totalConversionsCompleted == index {
print("completion happen \(images)")
}
})
}
}
3 ответа
У меня это работает, используя сингл
DispatchGroup
. Это моя реализация метода делегата:
func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
picker.dismiss(animated: true) // dismiss a picker
let imageItems = results
.map { $0.itemProvider }
.filter { $0.canLoadObject(ofClass: UIImage.self) } // filter for possible UIImages
let dispatchGroup = DispatchGroup()
var images = [UIImage]()
for imageItem in imageItems {
dispatchGroup.enter() // signal IN
imageItem.loadObject(ofClass: UIImage.self) { image, _ in
if let image = image as? UIImage {
images.append(image)
}
dispatchGroup.leave() // signal OUT
}
}
// This is called at the end; after all signals are matched (IN/OUT)
dispatchGroup.notify(queue: .main) {
print(images)
// DO whatever you want with `images` array
}
}
1 - Вы установили свой контроллер как делегат PHPickerViewController ?
Для этого ваш контроллер должен соответствовать PHPickerViewControllerDelegate.
class ViewController: UIViewController, PHPickerViewControllerDelegate {
И вы должны установить свой контроллер как делегат PHPickerViewController
pickerController.delegate = self //if you create PHPickerViewController inside your viewController
И тогда вы получите результаты по этому методу
func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
2 - Если вы не можете получить множественный выбор, вы можете изменить предел выбора объекта PHPickerConfiguration, который вы используете с вашим PHPickerViewController.
var confing = PHPickerConfiguration(photoLibrary: PHPhotoLibrary.shared())
confing.selectionLimit = 5
let pickerController = PHPickerViewController(configuration: confing)
3 - А затем вы можете работать с объектами в массиве результатов
let identifiers = results.compactMap(\.assetIdentifier)
let fetchResult = PHAsset.fetchAssets(withLocalIdentifiers: identifiers, options: nil)
Получить выбранный порядок изображений списка из PHPickerViewController:
func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
dismiss(animated: true)
var images = [UIImage]()
let dispatchGroup = DispatchGroup()
var assets: [PHAsset] = []
let identifiers = results.compactMap(\.assetIdentifier)
for id in identifiers {
dispatchGroup.enter()
let fetchResult = PHAsset.fetchAssets(withLocalIdentifiers: [id], options: nil)
if let result = fetchResult.firstObject {
assets.append(result)
}
dispatchGroup.leave()
}
dispatchGroup.notify(queue: .main, execute: { [weak self] in
for asset in assets {
if let image = self?.toImage(asset: asset) {
images.append(image)
}
}
print("Array image: \(images)")
})
}
func toImage(asset: PHAsset) -> UIImage? {
let manager = PHImageManager.default()
let options = PHImageRequestOptions()
options.deliveryMode = .highQualityFormat
options.isSynchronous = true
var result: UIImage? = nil
manager.requestImage(for: asset, targetSize: PHImageManagerMaximumSize, contentMode: .aspectFit, options: options, resultHandler: { (image, _) in
if let selectedImage = image {
result = selectedImage
}
})
return result
}
Надеюсь помочь вам, ребята