Cado21
Cado21

Reputation: 73

How can i get PHAsset from PHPickerResult? iOS 14

So, I found similar questions asked before but when I tried the same way as what I got, and it does not work as I expected, so what I'm trying to do is, I want to get PHAsset from PHPickerResult from PHPickerViewController.

so experimenting it using this source as my base code, and combined it with what I got from this.

also already add "Privacy - Photo Library Usage Description" to the info.plist when i tried this.

The code look like this.


import UIKit
import PhotosUI

class ViewController: UIViewController {
    
    @IBOutlet weak var myImageView: UIImageView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
    }
    
    @IBAction func buttonDidTap(_ sender: Any) {
        var configuration = PHPickerConfiguration()
        configuration.selectionLimit = 1
        configuration.filter = .any(of: [.images, .videos])
        
        let picker = PHPickerViewController(configuration: configuration)
        picker.delegate = self
        self.present(picker, animated: true, completion: nil)
    }
}

extension ViewController: PHPickerViewControllerDelegate {
    
    func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
        
        picker.dismiss(animated: true)
        let identifiers = results.compactMap(\.assetIdentifier)
        let fetchResult = PHAsset.fetchAssets(withLocalIdentifiers: identifiers, options: nil)
        fetchResult.enumerateObjects { (asset, index, stop) -> Void in
            PHImageManager.default().requestImage(for: asset,
                                                  targetSize: CGSize.init(width: 20, height: 20),
                                                  contentMode: PHImageContentMode.aspectFit,
                                                  options: nil) { (image: UIImage?, _: [AnyHashable : Any]?) in
                self.myImageView.image = image
            }
       }
    }
}

After I try to debug the code, I found out that the code inside fetchResult.enumerateObjects was not called that's why I can't get the image.

Or maybe I got the wrong syntax? can someone help me?

Upvotes: 6

Views: 9189

Answers (3)

Abdul Samad Butt
Abdul Samad Butt

Reputation: 37

You can use this custom class ImagePickerManager:

import Foundation
import UIKit
import PhotosUI

class ImagePickerManager: NSObject, PHPickerViewControllerDelegate, UINavigationControllerDelegate {

var picker: PHPickerViewController?
var pickImageCallback : ((UIImage) -> ())?
var viewController: UIViewController?

override init(){
    super.init()
}

func pickSingleImage(_ viewController: UIViewController, _ callback: @escaping ((UIImage) -> ())) {
    pickImageCallback = callback
    self.viewController = viewController
    
    var configuration = PHPickerConfiguration()
    configuration.filter = .any(of: [.images, .livePhotos])
    configuration.selectionLimit = 1
    picker = PHPickerViewController(configuration: configuration)
    picker?.delegate = self
    viewController.present(picker!, animated: true, completion: nil)
}

func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
    picker.dismiss(animated: true) {
        let itemProviders = results.map(\.itemProvider)
        for item in itemProviders {
            if item.canLoadObject(ofClass: UIImage.self) {
                item.loadObject(ofClass: UIImage.self) { (image, error) in
                    DispatchQueue.main.async {
                        if let image = image as? UIImage {
                            self.pickImageCallback!(image)
                        }
                    }
                }
            }
        }
    }
  }
}

Usage:

In the view controller initialise a variable:

let imagePicker = ImagePickerManager()

On the button action paste this line

ImagePickerManager().pickSingleImage(self) { pickedImage in
        self.myImageView.image = pickedImage
    }

Upvotes: -1

Abdul Samad Butt
Abdul Samad Butt

Reputation: 37

matt might be saying right but one more thing that you can do is the following. In this way image will be directly shown in the UIImageView with the same configuration that you have done.

func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
    dismiss(animated: true)
    let itemProviders = results.map(\.itemProvider)
    for item in itemProviders {
        if item.canLoadObject(ofClass: UIImage.self) {
            item.loadObject(ofClass: UIImage.self) { (image, error) in
                DispatchQueue.main.async {
                    if let image = image as? UIImage {       
                        self.myImageView.image = image
                    }
                }
            }
        }
    }
}

Upvotes: 0

matt
matt

Reputation: 535138

If you need an asset later, you have to initialize the configuration with the photo library. So this line is wrong:

var configuration = PHPickerConfiguration()

You want:

var configuration = PHPickerConfiguration(photoLibrary: PHPhotoLibrary.shared())

Upvotes: 14

Related Questions