8

UIImagePickerControllerReferenceURL was deprecated in iOS 11 (even though it's still returned in the info dictionary) and was supposed to be replaced with UIImagePickerControllerPHAsset, but I've yet to get an info dictionary back which contains that key. Since the one is deprecated and the other is missing, is there a known solution for extracting the "date taken" from the picked image?

For reference, this is an example info dictionary returned when and image is picked from the library:

▿ 4 elements
  ▿ 0 : 2 elements
    - key : "UIImagePickerControllerImageURL"
    - value : file:///private/var/mobile/Containers/Data/Application/EE1BA60E-2DC3-47C5-A58D-86498E95C323/tmp/3A025D4C-B378-474B-8A09-017479A3A776.jpeg
  ▿ 1 : 2 elements
    - key : "UIImagePickerControllerMediaType"
    - value : public.image
  ▿ 2 : 2 elements
    - key : "UIImagePickerControllerReferenceURL"
    - value : assets-library://asset/asset.HEIC?id=537976CD-A550-41C9-9416-92C8072112D7&ext=HEIC
  ▿ 3 : 2 elements
    - key : "UIImagePickerControllerOriginalImage"
    - value : <UIImage: 0x1d04b4760> size {3024, 4032} orientation 3 scale 1.000000

(Note that UIImagePickerControllerReferenceURL is still present, though deprecated, and the suggested replacement, UIImagePickerControllerPHAsset, is missing.)

If it were present, getting the date would be simple:

if let asset = info[UIImagePickerControllerPHAsset] as? PHAsset,
    let resource = PHAssetResource.assetResources(for: asset).first {
    let dateTaken = resource.creationDate
}

Could it be that Apple forgot to implement UIImagePickerControllerPHAsset? Any ideas on workarounds (without using deprecated methods)?

Note on possible duplicates

I believe that previous solutions on Stack Overflow are deprecated, and thus won't answer the question using modern approaches.

halfer
  • 19,824
  • 17
  • 99
  • 186
Clay Ellis
  • 4,960
  • 2
  • 37
  • 45
  • 2
    Looks like there's an open RADR for this since September 13. https://github.com/lionheart/openradar-mirror/issues/18370 –  Nov 16 '17 at 00:04
  • I see the same behavior. 4 keys if selecting photo from library, and 3 keys if taking a fresh photo (MediaType, OriginalImage and MediaMetadata). I dont see the PHAsset key. I have the permissions for photos and camera set. Is there some other permission we need to set? – Paulus Mar 22 '18 at 11:00

2 Answers2

4

Swift 4.1

I struggled with this for a while too. It turns out you just need user permission to access to the photo library - then info will contain a value for the key UIImagePickerControllerPHAsset. You can check & request access like this:

let status = PHPhotoLibrary.authorizationStatus()

switch status {
    case .authorized:
    // show your media picker
    case .denied:
    // probably alert the user that they need to grant photo access
    case .notDetermined:
    PHPhotoLibrary.requestAuthorization({status in
        if status == .authorized {
            // show your media picker
        }
    })
    case .restricted:
    // probably alert the user that photo access is restricted
}

Then you use the imagePickerController(_: didFinishPickingMediaWithInfo:) method as usual and will have access to the UIImagePickerControllerPHAsset

Trev14
  • 3,626
  • 2
  • 31
  • 40
3

You can get the date by examining the chosen photo's metadata through the ImageIO framework.

However, the claim that the PHAsset information doesn't arrive is simply bogus. It arrives just fine. You didn't show your code, so who knows what you're doing? Perhaps the problem is that you forgot to get user authorization? Without user authorization, of course you can't access the PHAsset. You'll get the UIImagePickerControllerOriginalImage and the UIImagePickerControllerImageURL and that's all.

This code works just fine for me (assuming we have the necessary user authorization before using the image picker controller in the first place):

func imagePickerController(_ picker: UIImagePickerController,
                           didFinishPickingMediaWithInfo info: [String : Any]) { //
    let asset = info[UIImagePickerControllerPHAsset] as? PHAsset
    let url = info[UIImagePickerControllerMediaURL] as? URL
    var im = info[UIImagePickerControllerOriginalImage] as? UIImage
    if let ed = info[UIImagePickerControllerEditedImage] as? UIImage {
        im = ed
    }
    let live = info[UIImagePickerControllerLivePhoto] as? PHLivePhoto
    let imurl = info[UIImagePickerControllerImageURL] as? URL
    self.dismiss(animated:true) {
        if let style = asset?.playbackStyle { // and so on, works fine
            // ....
        }
    }
}
matt
  • 515,959
  • 87
  • 875
  • 1,141
  • 1
    In no way does the above answer my question. It's just a bunch of code fluff. – Clay Ellis Nov 21 '17 at 18:32
  • It's code fluff that works perfectly. Anyway, it's not fluff; what I'm showing you is what you should be doing. Think about it. I can get the PHAsset. I can get the metadata. I can get the media URL. And that's because I got _user authorization_. It answers the question exactly. I'm doing it right and you're _not_. Do it right. – matt Nov 21 '17 at 18:33
  • 1
    Really? Because it doesn't demonstrate extracting the date taken from the metadata. I've made it clear, `UIImagePickerControllerPHAsset` isn't present in `info`, and I've requested and received the correct permissions. Dude, go be upset at someone else's post. I won't be responding any further. – Clay Ellis Nov 21 '17 at 18:35
  • 2
    Well, the PHAsset _is_ present when I run my code. That's just a fact. And you can see me obtaining its `playbackStyle` in the last line I showed. You can download the example project and run it for yourself. – matt Nov 21 '17 at 18:43
  • This answer works for me as well. Both within the simulator and on the device, using the most current Xcode 9.1 – Klaas Nov 22 '17 at 08:47
  • 1
    How do you get the authorization? using `NSPhotoLibraryUsageDescription`? @matt – Akshit Zaveri Nov 30 '17 at 07:38
  • @AkshitZaveri https://developer.apple.com/documentation/photos/phphotolibrary/1620736-requestauthorization – matt Nov 30 '17 at 15:52