Improved version on Objective C, using blocks. It creates an album, if it doesn't exist, then saves three types of media items - photos, gifs and videos:
// Types of media, that can be saved to an album
typedef NS_ENUM(NSUInteger, AlbumMediaType) {
AlbumMediaTypePhoto,
AlbumMediaTypeGIF,
AlbumMediaTypeVideo
};
/**
Creates album if it doesn't exist and returns it in a block
*/
- (void)createCollectionOnComplete:(void (^ _Nonnull)(PHAssetCollection * _Nonnull collection))onComplete
{
NSString *albumTitle = @"YOUR_ALBUM_TITLE";
__block PHAssetCollection *collection;
__block PHObjectPlaceholder *placeholder;
// Searching for an existing album
PHFetchOptions *fetchOptions = [[PHFetchOptions alloc] init];
fetchOptions.predicate = [NSPredicate predicateWithFormat:@"title = %@", albumTitle];
collection = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeAlbum
subtype:PHAssetCollectionSubtypeAny
options:fetchOptions].firstObject;
// If album is not found, we create it
if (!collection)
{
[[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
PHAssetCollectionChangeRequest *createAlbum = [PHAssetCollectionChangeRequest creationRequestForAssetCollectionWithTitle:albumTitle];
placeholder = [createAlbum placeholderForCreatedAssetCollection];
} completionHandler:^(BOOL success, NSError *error) {
if (success)
{
PHFetchResult *collectionFetchResult = [PHAssetCollection fetchAssetCollectionsWithLocalIdentifiers:@[placeholder.localIdentifier]
options:nil];
collection = collectionFetchResult.firstObject;
// After creating album, we return it
onComplete(collection);
}
}];
} else {
// If album already exists, we instantly return it
onComplete(collection);
}
}
/**
Saves an item of a given mediatype, that is located in mediaURL
*/
- (void)saveToAlbumMediaItemFromURL:(NSURL *)mediaURL mediaType:(AlbumMediaType)mediaType
{
NSData *mediaData = [NSData dataWithContentsOfURL:mediaURL];
if (!mediaData) {
OWSFail(@"%@ Could not load data: %@", self.logTag, [self.attachmentStream mediaURL]);
return;
}
[self createCollectionOnComplete:^(PHAssetCollection * _Nonnull collection) {
[[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
// We create a PHAsset using creationRequest
PHAssetCreationRequest *assetRequest;
switch (mediaType) {
case AlbumMediaTypePhoto: {
assetRequest = [PHAssetCreationRequest creationRequestForAssetFromImage:[UIImage imageWithData:mediaData]];
break;
}
case AlbumMediaTypeGIF: {
assetRequest = [PHAssetCreationRequest creationRequestForAsset];
PHAssetResourceCreationOptions *options = [[PHAssetResourceCreationOptions alloc] init];
[assetRequest addResourceWithType:PHAssetResourceTypePhoto data:mediaData options:options];
break;
}
case AlbumMediaTypeVideo: {
if ( !UIVideoAtPathIsCompatibleWithSavedPhotosAlbum(mediaURL.path) ) {
OWSFail(@"%@ Could not save incompatible video data.", self.logTag);
break;
}
NSString *videoPath = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) objectAtIndex:0] stringByAppendingPathComponent:@"file.mov"];
[mediaData writeToFile:videoPath atomically:YES];
assetRequest = [PHAssetCreationRequest creationRequestForAssetFromVideoAtFileURL:[NSURL fileURLWithPath:videoPath]];
break;
}
default:
break;
}
// Creating a request to change an album
PHAssetCollectionChangeRequest *albumChangeRequest = [PHAssetCollectionChangeRequest changeRequestForAssetCollection:collection];
// PHAsset is not created yet, so we use a placeholder
PHObjectPlaceholder *placeholder = [assetRequest placeholderForCreatedAsset];
// We add a placeholder of a created item to the request of changing album
if (albumChangeRequest != nil && placeholder != nil) {
[albumChangeRequest addAssets: @[placeholder]];
}
} completionHandler:^(BOOL success, NSError *error) {
if (success) {
NSLog(@"Media item saved!");
} else {
NSLog(@"Error saving media item - %@", error ? error.localizedDescription : @"");
}
}];
}];
}
We can use these methods to save media items this way:
[self saveToAlbumMediaItemFromURL:[self.attachmentStream mediaURL] mediaType:AlbumMediaTypeGIF];
ALAssetsLibrary
category. Looks like there are some useful comments below the article that may assist with performance also.