10

Selecting images in Photos.app to pass to an action extension seems to yield paths to images on disk (e.g.: file:///var/mobile/Media/DCIM/109APPLE/IMG_9417.JPG). Is there a way to get the corresponding ALAsset or PHAsset?

The URL looks like it corresponds to the PHImageFileURLKey entry you get from calling PHImageManager.requestImageDataForAsset. I'd hate to have to iterate through all PHAssets to find it.

Duc
  • 487
  • 1
  • 7
  • 15
  • That's an NSURL. Do you not see how to get from there to a PHAsset? – matt Feb 22 '15 at 19:06
  • I don't. There's `fetchAssetsWithALAssetURLs` but that only takes the `assets-library://` URLs. – Duc Feb 22 '15 at 19:10
  • Hmm, it's even worse than that. You can't even get into the library this way because of sandboxing. – matt Feb 22 '15 at 19:39
  • What about ALAssetsLibrary `assetForURL`? – matt Feb 22 '15 at 19:52
  • Also requires the assets-library scheme (not that that stopped me: I tried both `assetForURL` and `fetchAssetsWithALAssetURLs` for kicks; no dice). – Duc Feb 22 '15 at 20:00
  • I may be on the crazy-limb here, but it seems like there is _no way_ that all those photo extensions in iOS 8 are being handed file URLs and doing what they do. Did you ask _that_ question? – Clay Bridges Mar 06 '15 at 22:14
  • Right. A photo-editing extension does in fact give you the PHAsset (or some other PhotoKit thing). However, I want to play with multiple photos simultaneously (i.e., hit the Select button and tap a few photos) and for that you need a share or action extension. For those I can see why having the file is useful: you're probably uploading them somewhere or doing some processing on the actual data. – Duc Mar 06 '15 at 22:21

2 Answers2

5

I did what I didn't want to do and threw this dumb search approach together. It works, although it's horrible, slow and gives me memory issues when the photo library is large.

As a noob to both Cocoa and Swift I'd appreciate refinement tips. Thanks!

func PHAssetForFileURL(url: NSURL) -> PHAsset? {
    var imageRequestOptions = PHImageRequestOptions()
    imageRequestOptions.version = .Current
    imageRequestOptions.deliveryMode = .FastFormat
    imageRequestOptions.resizeMode = .Fast
    imageRequestOptions.synchronous = true

    let fetchResult = PHAsset.fetchAssetsWithOptions(nil)
    for var index = 0; index < fetchResult.count; index++ {
        if let asset = fetchResult[index] as? PHAsset {
            var found = false
            PHImageManager.defaultManager().requestImageDataForAsset(asset,
                options: imageRequestOptions) { (_, _, _, info) in
                    if let urlkey = info["PHImageFileURLKey"] as? NSURL {
                        if urlkey.absoluteString! == url.absoluteString! {
                            found = true
                        }
                    }
            }
            if (found) {
                return asset
            }
        }
    }

    return nil
}
Duc
  • 487
  • 1
  • 7
  • 15
1

So this is commentary on ("refinement tips") to your auto-answer. SO comments don't cut it for code samples, so here we go.

  1. You can replace your for-index loop with a simpler for-each loop. E.g. something like:

    for asset in PHAsset.fetchAssetsWithOptions(nil)
    
  2. As of the last time I checked, the key in info["PHImageFileURLKey"] is undocumented. Be apprised. I don't think it will get you rejected, but the behavior could change at any time.

Clay Bridges
  • 11,602
  • 10
  • 68
  • 118
  • 1
    Thanks for the notes. I definitely prefer the for .. in syntax, but PHFetchResult doesn't implement the Generator protocol and can't be iterated that way (unless something's changed recently). – Duc Mar 06 '15 at 21:05
  • I couldn't get it to work. And [this answer](http://stackoverflow.com/a/25872991/170871) indicates you need SequenceType (not Generator, turns out) to make even NSFastEnumeration-conformant types iterable. – Duc Mar 06 '15 at 22:15
  • Edited comment, out of order: @Soybean I can only speak to Objective-C right now, but there, it would be `NSFastEnumeration`, and yes it does: `@interface PHFetchResult : NSObject ` :) – Clay Bridges Mar 06 '15 at 22:15