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
}

Надеюсь помочь вам, ребята

Другие вопросы по тегам