Add new Asset to a new Asset Collection within one Change Block - ios

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

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

Related

Memory leak when using placeholderForCreatedAsset property in PHAssetChangeRequest

In iOS 10 I start to replace asset-library to PhotoKit to manage image picker. But there is an issue.
The specific step is that app needs system camera and user shot a photo after that the delegate method imagePickerController:didFinishPickingMediaWithInfo: will be called.
Then, here is my code:
UIImage *pickerImage = [[info objectForKey:UIImagePickerControllerOriginalImage] fixOrientation];
PHPhotoLibrary *photoLibrary = [PHPhotoLibrary sharedPhotoLibrary];
__block NSString *localId;
[photoLibrary performChanges:^{
PHAssetChangeRequest *assetChangeRequest = [PHAssetChangeRequest creationRequestForAssetFromImage:pickerImage];
localId = [[assetChangeRequest placeholderForCreatedAsset] localIdentifier];
} completionHandler:^(BOOL success, NSError * _Nullable error) {
if (success) {
// to get localIdentifier and reload collectionView
}
}];
line 1 that fixOrientation is a custom category that return UIImage instance.
Only call [PHAssetChangeRequest creationRequestForAssetFromImage:] method performs fine. However, when I want to fetch newly created photo to use [assetChangeRequest placeholderForCreatedAsset] , it shows memory leak and app crash.
Above all, any solution to fetch created photo just moment or other methods to solve that by using Photos Framework?

How to delete image from PHAssetCollection?

I have PHAssetCollection in my application which contain all albums of photos app.
Problem is that i can delete images from the All Photos but cant delete images from camera roll,favourites,screenshots etc..
Plz help me to delete from PHAssetCollection.
this is the code i did to delete images.
// Enable the trash button if the asset can be deleted.
BOOL isTrashable = NO;
if (self.assetCollection) {
isTrashable = [self.assetCollection canPerformEditOperation:PHCollectionEditOperationRemoveContent];
}
else {
isTrashable = [self.asset canPerformEditOperation:PHAssetEditOperationDelete];
}
self.trashButton.enabled = isTrashable;
[self updateImage];
reference from Apple developer forum
[[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
PHAssetCollectionChangeRequest *request = [PHAssetCollectionChangeRequest
changeRequestForAssetCollection:self.myAlbum
assets:self.albumAssetsFetchResult];
[request removeAssets:#[asset]];
} completionHandler:^(BOOL success, NSError *error) {
NSLog(#"Finished removing asset from the album. %#", (success ? #"Success" : error));
}];
or
// Delete asset from library
[[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
[PHAssetChangeRequest deleteAssets:#[self.asset]];
} completionHandler:completionHandler];
make sure isTrashable = YES
Comment the above code and set
self.trashbutton.enable=YES;
Images deleted from camera role also deleted from All Photos.

How to move/copy an image to another album in objective-c?

I am writing an app which at the moment should just be able to have images in an album, dedicated to the app. The user is able to add pictures to the folder from inside the app, either by choosing an existing image or taking a new one with the camera. This functionality is however very slow, so I am wondering if I am doing it correctly.
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
Calls this method with the chosen UIImage:
- (void)addPictureAndUpdate:(UIImage *)image{
PHFetchOptions *albumFetchOptions = [PHFetchOptions new];
albumFetchOptions.predicate = [NSPredicate predicateWithFormat:#"%K like %#", #"title", self.albumName];
PHFetchResult *album = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeAlbum subtype:PHAssetCollectionSubtypeAlbumRegular options:albumFetchOptions];
PHAssetCollection *assetCollection = album.firstObject;
[[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
PHAssetChangeRequest *assetChangeRequest = [PHAssetChangeRequest creationRequestForAssetFromImage:image];
PHAssetCollectionChangeRequest *assetCollectionChangeRequest = [PHAssetCollectionChangeRequest changeRequestForAssetCollection:assetCollection];
[assetCollectionChangeRequest addAssets:#[[assetChangeRequest placeholderForCreatedAsset]]];
} completionHandler:^(BOOL success, NSError *error) {
if (!success) {
NSLog(#"Error creating asset: %#", error);
} else {
//Add PHAsset to datasource
//Update view
}
}];
This(the finishing of the ChangeRequest) is very slow, like 20-30 seconds and even more at times.
What am doing wrong? I am quite new to iOS development and obviously to the new Photos framework and I really want to learn how to do this.
Would it be smarter to seperate the two things, the showing the image and moving it? At the moment, I am storing a PHAsset for each image, which is then loaded in the requested size when needed(a thumbnail size for showing in the view and the original size when it is shown in fullscreen). Would it be smarter to always just store a UIImage, and then change the size of that? That way, I would be able to make the request to add the asset to the album, and immediatly show it as I would just add the UIImage to the datasource.
My main concerns about this are memory problems and iamge scaling problems. Would storing UIImages for an entire album be too memory heavy for an app? And, is it easy to resize a UIImage for display?
Thank you

How to save GPS data with a taken photo in ios

I am developing a camera application which can be used to take pictures and save them in a separate album. I used photos framework to save images and now I need to save GPS data (location where the picture is taken) with the picture (may be in metadata). I searched for any method to do this thing using photos framework but I failed, I couldn't find anything related. Any help would be highly appreciated.
This is the peace of code I used to save pictures
[[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
PHAssetChangeRequest *assetRequest = [PHAssetChangeRequest creationRequestForAssetFromImage:capturedImage];
placeholder = [assetRequest placeholderForCreatedAsset];
photosAsset = [PHAsset fetchAssetsInAssetCollection:Album options:nil];
PHAssetCollectionChangeRequest *albumChangeRequest = [PHAssetCollectionChangeRequest changeRequestForAssetCollection:Album assets:photosAsset];
[albumChangeRequest addAssets:#[placeholder]];
} completionHandler:^(BOOL success, NSError *error) {
if (success)
{
}
else
{
}
}];
I assume you want the latitude & longitude. Have you tried the location property of PHAsset class?

delete one video from asset or album

How can delete one video from asset/album in iOS8
When I use UIImagePickerController for purpose of selection
then I select one Video from asset/album
in Info Dictionary I got response on didFinishPickingMediaWithInfo method
{
UIImagePickerControllerMediaType = "public.movie";
UIImagePickerControllerMediaURL = "file:///Users/appaspect2/Library/Developer/CoreSimulator/Devices/A61DFE3B-8BA0-4A18-939A-2B0BC2F6084E/data/Containers/Data/Application/69E55783-CB4F-4620-9C81-B3948F5A843B/tmp/trim.1202C1FA-6130-4BC7-AA31-391CC7E0D7B6.MOV";
UIImagePickerControllerReferenceURL = "assets-library://asset/asset.MOV?id=189B68BD-17D0-4665-A065-11A40B0F2B25&ext=MOV";
}
I want to delete file this file which is select in UIImagePickerControllerReferenceURL or asset/album video
AssestsLibrary do not have any such method. But after searching about this I found in ios8 deleting photos might be possible using the Photos Framework
Check the documentation of Photos Framework
For deleting assets refer to PHAssetChangeRequest
+ (void)deleteAssets:(id<NSFastEnumeration>)assets
Finally so much effort I am enable to delete file of asset/album video for iOS8 Only.
You can add this in didFinishPickingMediaWithInfo Method
PHFetchResult *asset = [[PHAsset fetchAssetsWithALAssetURLs:#[info[#"UIImagePickerControllerReferenceURL"]] options:nil] firstObject];
NSLog(#"asset %#",asset);
[self toggleFavoriteForAsset:(PHAsset *)asset];
and Add One Method For Delete Asset Video
- (void)toggleFavoriteForAsset:(PHAsset *)asset {
[[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
// Create a change request from the asset to be modified.
BOOL req = [asset canPerformEditOperation:PHAssetEditOperationDelete];
if (req) {
NSLog(#"true");
[PHAssetChangeRequest deleteAssets:#[asset]];
}
} completionHandler:^(BOOL success, NSError *error) {
NSLog(#"Finished Delete asset. %#", (success ? #"Success." : error));
}];
}

Resources