4

After looking into the PHPhotoLibrary Framework, I've been able to successfully create and add new image assets and collections but the issue I've run into is not being able to successfully create a new Asset Collection AND add a new Asset to in within the same change block.

If I create an album as an Asset Collection in one change block, and then on completion, create an image as an Asset in another change block it works as expected. Additionally if I have an album already and query that album, I can add an image as an Asset to that album successfully.

The PHAssetCollectionChangeRequest Class Documentation states:

To add assets to the newly created asset collection or change its title, use the methods listed in Modifying Asset Collections. To reference the newly created asset collection later in the same change block or after the change block completes, use the placeholderForCreatedAssetCollection property to retrieve a placeholder object.

I've either misread it or it doesn't actually have the ability to do as it says - to add assets to a newly created asset collection.

This following code completes "successfully" in the completion handler, but when going into the iOS Photos.app, only the Album is created, with no image added (though the image is added to the camera roll as expected).

The thing that's causing the issue is that a PHObjectPlaceholder can't be used as a PHAssetCollection, so the "reference" they speak of can't be used in this way, so that's the underlying problem I've failed to understand:

[[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{

    // Create the Asset Creation Request to save the photo to the user's photos - This will add it to the camera roll at the very least
    PHAssetChangeRequest *imageCreationRequest = [PHAssetChangeRequest creationRequestForAssetFromImage:image];

    // Create the Asset Collection Creation Request to create the new album - This will create the album at the very least
    PHAssetCollectionChangeRequest *creationRequest = [PHAssetCollectionChangeRequest creationRequestForAssetCollectionWithTitle:@"New Album"];
    PHObjectPlaceholder *collectionPlaceholder = creationRequest.placeholderForCreatedAssetCollection; // Get the placeholder Asset Collection

    // Create the Asset Collection Change Request to add the new image Asset to the new album Asset Collection
    // Warns about PHObjectPlaceholder* != PHAssetCollection*
    PHAssetCollectionChangeRequest *albumChangeRequest = [PHAssetCollectionChangeRequest changeRequestForAssetCollection:collectionPlaceholder];
    [albumChangeRequest addAssets:@[imageCreationRequest.placeholderForCreatedAsset]];

} completionHandler:^(BOOL success, NSError * _Nullable error) {
    if (success) {
        NSLog(@"Saved to iOS Photos after creating album");
    }
}];

If it helps, this is the code which works using two change blocks:

__block PHObjectPlaceholder *collectionPlaceholder;

[[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{

    // Create the Asset Collection Creation Request to create the new album - This will create the album at the very least
    PHAssetCollectionChangeRequest *creationRequest = [PHAssetCollectionChangeRequest creationRequestForAssetCollectionWithTitle:@"New Album"];
    collectionPlaceholder = creationRequest.placeholderForCreatedAssetCollection; // Get the placeholder Asset Collection

} completionHandler:^(BOOL success, NSError * _Nullable error) {

    if (success) {
        [[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{

            // Create the Asset Creation Request to save the photo to the user's photos - This will add it to the camera roll at the very least
            PHAssetChangeRequest *imageCreationRequest = [PHAssetChangeRequest creationRequestForAssetFromImage:image];

            // Get the album collection using the placeholder identifier from the first change block
            PHAssetCollection *collection = [PHAssetCollection fetchAssetCollectionsWithLocalIdentifiers:@[collectionPlaceholder.localIdentifier] options:nil].firstObject;

            // Create the Asset Collection Change Request to add the new image Asset to the new album Asset Collection
            PHAssetCollectionChangeRequest *albumChangeRequest = [PHAssetCollectionChangeRequest changeRequestForAssetCollection:collection];
            [albumChangeRequest addAssets:@[imageCreationRequest.placeholderForCreatedAsset]];

        } completionHandler:^(BOOL success, NSError * _Nullable error) {

            if (success) {
                NSLog(@"Saved to iOS Photos after creating album");
            } else {
                NSLog(@"Couldn't save to iOS Photos after creating album (%@)", error.description);
            }

        }];
    }

}];
Ohifriend
  • 352
  • 4
  • 10
  • Did you find a solution to this? – Piers Geyman Oct 31 '17 at 18:49
  • @PiersGeyman I haven't tried anything new since August last year to be honest. Considering this was back in iOS 8 (according to my tag that I don't remember why I added), maybe there's been an update to allow you to do it, however if you tried recently and are having the same outcome then it's likely just how it is. I settled with the solution in my question. – Ohifriend Nov 01 '17 at 23:04
  • Anyone coming back to this, I've given up on the placeholder crap, and just break it up into multiple change blocks. I don't even hand around a reference to a collection. Just look it up and get it each time. This API is the sloppiest, most poorly documented, clunkiest, crappiest, low-quality thing I've ever seen come out of apple and it's dumb. – ChrisH Jan 05 '21 at 15:46

1 Answers1

0

Have you tried converting the album's placeholder into an album inside the one change request?

  PHAssetCollection *collection = [PHAssetCollection fetchAssetCollectionsWithLocalIdentifiers:@[collectionPlaceholder.localIdentifier] options:nil].firstObject;

  PHAssetCollectionChangeRequest *albumChangeRequest = [PHAssetCollectionChangeRequest changeRequestForAssetCollection:collection];
Adam Tegen
  • 25,378
  • 33
  • 125
  • 153
  • I don't remember if I tried this before posting or not, but I've just attempted to do this now and it also returns an error (doesn't even add the photo to the camera roll). – Ohifriend Aug 04 '16 at 01:47
  • Years later, this entire model is still a kludgey train wreck that is barely worth even using. :( – ChrisH Jan 05 '21 at 15:25