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);
}
}];
}
}];