Search code examples
iosphotosframework

Save UIImage to PHAssetCollection


I am using the following code to attempt to save a new image to a PHAssetCollection, specifically, the Camera Roll (aka User Library) :

[[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
    PHAssetChangeRequest *assetChangeRequest = [PHAssetChangeRequest creationRequestForAssetFromImage:image];

    PHFetchResult *fetchResult = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeSmartAlbum subtype:PHAssetCollectionSubtypeSmartAlbumUserLibrary options:nil];
    PHAssetCollection *assetCollection = fetchResult[0];

    if (assetCollection) {
        PHAssetCollectionChangeRequest *assetCollectionChangeRequest = [PHAssetCollectionChangeRequest changeRequestForAssetCollection:assetCollection];
        [assetCollectionChangeRequest addAssets:@[[assetChangeRequest placeholderForCreatedAsset]]];
    }
} completionHandler:^(BOOL success, NSError *error) {
    if (!success) {
        NSLog(@"Error creating asset: %@", error);
    }
}];

I always get an error.

All of the objects in the perform block look fine:

(lldb) po image
<UIImage: 0x174289ec0>, {1080, 1466}

(lldb) po assetCollection
<PHAssetCollection: 0x1741d5540> F6705124-D49B-4FDC-9191-7E84CFCCD148/L0/040 Camera Roll assetCollectionType=2/209

(lldb) po assetCollectionChangeRequest
<PHAssetCollectionChangeRequest: 0x170264640> title=(null) hasAssetChanges=1

And the error message is pretty useless:

The operation couldn’t be completed. (Cocoa error -1.)

How can I successfully save my new image to the user's library? Thanks.


Solution

  • In general you're doing things in the wrong order; you should not be doing any fetching inside a performChanges block. And you don't have to, in any case. Do not fetch the collection at all. Just create the photo, plain and simple, exactly as in your first line - except that you don't even need to keep a reference to the change request:

    [PHAssetChangeRequest creationRequestForAssetFromImage:image];
    

    ...and stop. At that point the photo has been added to the camera roll.

    I just tried this and it works perfectly.

    (Of course I'm assuming you have already obtained the necessary permissions from the user...!)