How to get the URL of an image just added in PHPhotoLibrary

11,675

Solution 1

I didn't find the way to get URL, but maybe localIdentifier can help you do the same work.

use

NSString* localId = [[assetChangeRequest placeholderForCreatedAsset] localIdentifier];

to get the local ID and get the image later.

__block NSString* localId;
// Add it to the photo library
[[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
    PHAssetChangeRequest *assetChangeRequest = [PHAssetChangeRequest creationRequestForAssetFromImage:image];

    if (self.assetCollection) {
        PHAssetCollectionChangeRequest *assetCollectionChangeRequest = [PHAssetCollectionChangeRequest changeRequestForAssetCollection:self.assetCollection];
        [assetCollectionChangeRequest addAssets:@[[assetChangeRequest placeholderForCreatedAsset]]];
    }
    localId = [[assetChangeRequest placeholderForCreatedAsset] localIdentifier];
} completionHandler:^(BOOL success, NSError *error) {
    PHFetchResult* assetResult = [PHAsset fetchAssetsWithLocalIdentifiers:@[localId] options:nil];
    if (!success) {
        NSLog(@"Error creating asset: %@", error);
    } else {
        PHFetchResult* assetResult = [PHAsset fetchAssetsWithLocalIdentifiers:@[localId] options:nil];
        PHAsset *asset = [assetResult firstObject];
        [[PHImageManager defaultManager] requestImageDataForAsset:asset options:nil resultHandler:^(NSData *imageData, NSString *dataUTI, UIImageOrientation orientation, NSDictionary *info) {
            UIImage* newImage = [UIImage imageWithData:imageData];
            self.imageView.image = newImage;
        }];
    }
}];

Solution 2

If we use the ALAssetsLibrary, it is very simple to save a picture in the Photo Album and get its URL:

    // Get the image
    UIImage *image = [info objectForKey:UIImagePickerControllerOriginalImage];

    // Add the image in the Photo Library
    ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
    [library writeImageToSavedPhotosAlbum: [image CGImage]
                              orientation: (ALAssetOrientation)[image imageOrientation]
                          completionBlock: ^(NSURL *assetURL, NSError *error)
    {
        if (error)
        {
            NSLog( @"error: %@", error );
        }
        else
        {
            NSLog( @"assetURL = %@", assetURL );
        }
    }];

But surprisingly it seems not possible to do the same thing with the new PHPhotoLibrary!

A solution to have the same result with PHPhotoLibrary is always welcome.

Solution 3

I don't like this fix, as this could result in a race condition. So far I can't think of a better solution. If someone does I'd love to hear it :) Either way, here is a Swift-version of Rigel Chen's answer

import Photos

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

    if let image = info[UIImagePickerControllerOriginalImage] as? UIImage {

        var localId:String?
        let imageManager = PHPhotoLibrary.sharedPhotoLibrary()

        imageManager.performChanges({ () -> Void in

            let request = PHAssetChangeRequest.creationRequestForAssetFromImage(image)
            localId = request.placeholderForCreatedAsset?.localIdentifier

            }, completionHandler: { (success, error) -> Void in
                dispatch_async(dispatch_get_main_queue(), { () -> Void in

                    if let localId = localId {

                        let result = PHAsset.fetchAssetsWithLocalIdentifiers([localId], options: nil)
                        let assets = result.objectsAtIndexes(NSIndexSet(indexesInRange: NSRange(location: 0, length: result.count))) as? [PHAsset] ?? []

                        if let asset = assets.first {
                            // Do something with result
                        }
                    }
                })
        })
    }
}
Share:
11,675

Related videos on Youtube

PatrickV
Author by

PatrickV

Updated on June 17, 2022

Comments

  • PatrickV
    PatrickV almost 2 years

    I am using the UIImagePickerController in two cases

    • to select an existing image in the Photo Library
    • to take a new picture

    In the first case, when I choose an image form the library, I can easily get the URL in the delegate method:

    - (void) imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
    {
        // Get the URL
        NSURL *url = [info valueForKey:UIImagePickerControllerReferenceURL];
        ...
    }
    

    But when I take a new picture, the image is not yet in the photo library and has no URL yet. So, I first need to add the image in the Library. But then, how to get the URL of the new asset?

    Here is my code to add the image in the Photo Library

    - (void) imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
    {
        // Get the image
        UIImage *image = [info objectForKey:UIImagePickerControllerOriginalImage];
    
        // Add the image in the library
        [[PHPhotoLibrary sharedPhotoLibrary]
    
            performChanges:^
            {
                // Request creating an asset from the image.
                PHAssetChangeRequest *createAssetRequest = [PHAssetChangeRequest creationRequestForAssetFromImage:image];
    
                // Get the URL of the new asset here ?
                ...
            }
    
            completionHandler:^(BOOL success, NSError *error)
            {
                if (!success) { ...; return; }
    
                // Get the URL of the new asset here ?
                ...
            }
        ];
    }
    
  • Kevin R
    Kevin R about 8 years
    This works, but feels very scary, I don't know if it will actually happen, but this approach could result in a race condition.
  • SunilG
    SunilG almost 8 years
    This is good I up voted but I am curios to know what benefit is this line doing let assets = result.objectsAtIndexes(NSIndexSet(indexesInRange: NSRange(location: 0, length: result.count))) as? [PHAsset] ?? [] we can still do result.firsObject
  • passol
    passol over 7 years
    ALAssetsLibrary somtimes cannot create group ,
  • Rudolf Real
    Rudolf Real about 7 years
    ALAssetsLibrary is deprecated and should not be used anymore.
  • Peter Lapisu
    Peter Lapisu almost 7 years
    what race condition? i wouldn't be sure if the localIdentifier is available yet
  • Moeez Akram
    Moeez Akram over 6 years
    hello can you please tell what will be the self.assetCollection here, what class it is, thanks