15

I'm trying to retrieve a PHAsset however PHAsset.fetchAssets(withALAssetURLs:options:) is deprecated from iOS 8 so how can I properly retrieve a PHAsset?

Peter Warbo
  • 11,136
  • 14
  • 98
  • 193

4 Answers4

20

I had the same the issue, first check permissions and request access:

let status = PHPhotoLibrary.authorizationStatus()

if status == .notDetermined  {
    PHPhotoLibrary.requestAuthorization({status in

    })
}

Just hook that up to whatever triggers your UIImagePickerController. The delegate call should now include the PHAsset in the userInfo.

guard let asset = info[UIImagePickerControllerPHAsset] as? PHAsset
  • 1
    This is available to iOS 11.0 and above. Any solution for lower versions of iOS? – Ishika Apr 12 '18 at 07:38
  • 3
    I get `nil` for this in the simulator. – mxcl Apr 27 '18 at 19:31
  • The info key enums have changed to be more Swift-like. Replace `UIImagePickerControllerPHAsset` with `UIImagePickerController.InfoKey.phAsset`, or just `.phAsset`. – commscheck Apr 04 '19 at 05:48
  • I had this problem on iPhone 6s but not on iPhone XSMax, after this suggestion works on 6S also, btw both iPhone's are on latest iOS 13.5 firmware – clopex May 29 '20 at 09:26
6

Here is my solution:

func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {

        if #available(iOS 11.0, *) {
               let asset = info[UIImagePickerControllerPHAsset]

        } else {
               if let assetURL = info[UIImagePickerControllerReferenceURL] as? URL {
               let result = PHAsset.fetchAssets(withALAssetURLs: [assetURL], options: nil)
               let asset = result.firstObject
               }
       }
}
Shahul Hasan
  • 300
  • 3
  • 2
3

The PHAsset will not appear in the didFinishPickingMediaWithInfo: info result unless the user has authorized, which did not happen for me just by presenting the picker. I added this in the Coordinator init():

            let status = PHPhotoLibrary.authorizationStatus()

            if status == .notDetermined  {
                PHPhotoLibrary.requestAuthorization({status in

                })
            }
David Tristram
  • 189
  • 1
  • 3
  • This helped! It's really not obvious you need to ask for authorization, because the picker shows up, and returns images even without it. – alekop Feb 27 '21 at 02:35
0

I am not sure what you want.

Are you trying to target iOS 8?

This is how I fetch photos and it works in iOS (8.0 and later), macOS (10.11 and later), tvOS (10.0 and later). Code is commented where it may be confusing

  1. The first functions sets the options to fetch the photos
  2. The second function will actually fetch them

     //import the Photos framework
     import Photos
     //in these arrays I store my images and assets
     var images = [UIImage]()
     var assets = [PHAsset]()
    
     fileprivate func setPhotoOptions() -> PHFetchOptions{
            let fetchOptions = PHFetchOptions()
            fetchOptions.fetchLimit = 15
            let sortDescriptor = NSSortDescriptor(key: "creationDate", ascending: false)
            fetchOptions.sortDescriptors = [sortDescriptor]
            return fetchOptions
        }
    
    
    
    
    fileprivate func fetchPhotos() {
    let allPhotos = PHAsset.fetchAssets(with: .image, options: setPhotoOptions())
    
    DispatchQueue.global(qos: .background).async {
    
        allPhotos.enumerateObjects({ (asset, count, stop) in
            let imageManager = PHImageManager.default()
            let targetSize = CGSize(width: 200, height: 200)
            let options = PHImageRequestOptions()
            options.isSynchronous = true
            imageManager.requestImage(for: asset, targetSize: targetSize, contentMode: .aspectFit, options: options, resultHandler: { (image, info) in
    
                if let image = image {
                    self.images.append(image)
                    self.assets.append(asset)
    
    
                }
    
                if count == allPhotos.count - 1 {
                    DispatchQueue.main.async {
                        //basically, here you can do what you want
                        //(after you finish retrieving your assets)
                        //I am reloading my collection view
                        self.collectionView?.reloadData()
                    }
                }
    
            })
    
    
        })
    
    }
    

    }

Edit based on OP's clarification

You need to set the delegate UIImagePickerControllerDelegate

then implement the following function

func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject]) {

within said method, get the image like this:

var image : UIImage = info[UIImagePickerControllerEditedImage] as! UIImage
Jesus Rodriguez
  • 2,571
  • 2
  • 22
  • 38