I am using setImageData to delete a photo in the following way :
[asset setImageData:nil metadata:nil completionBlock:^(NSURL *assetURL, NSError *error)
{
// Do something
}];
This code was working perfectly fine in iOS 8.2 and earlier versions.
But, in 8.3 it gives the error :
#"Error Domain=ALAssetsLibraryErrorDomain Code=-3311 \"User denied access\" UserInfo=0x175061ac0 {NSLocalizedFailureReason=The user has denied the application access to their media., NSLocalizedDescription=User denied access, NSUnderlyingError=0x17025d700 \"The operation couldn’t be completed. (ALAssetsLibraryErrorDomain error -3311.)\”}"
I tried replacing the image data and metadata fields with some valid image data instead of “nil”. Still it gives the same error!!
Is this some bug in iOS 8.3? Is there any workaround?
Thanks in anticipation.
Another important information :
[PHPhotoLibrary authorizationStatus] returns "PHAuthorizationStatusAuthorized".
[ALAssetsLibrary authorizationStatus] also returns "ALAuthorizationStatusAuthorized".
As far as I know, the setImageData method was never intended to be used as a method for deleting assets. It is possible that on iOS 8.3 Apple patched things up so this no longer works.
I recommend that you look into using the Photos framework which includes a dedicated method for deleting assets.
Here's an example:
-(void)deleteAssetWithURL:(NSString*)assetURLString
{
NSURL *assetURL = [NSURL URLWithString:assetURLString];
if (assetURL == nil)
{
return;
}
PHFetchResult *result = [PHAsset fetchAssetsWithALAssetURLs:#[assetURL] options:nil];
if (result.count > 0)
{
PHAsset *phAsset = result.firstObject;
if ((phAsset != nil) && ([phAsset canPerformEditOperation:PHAssetEditOperationDelete]))
{
[[PHPhotoLibrary sharedPhotoLibrary] performChanges:^
{
[PHAssetChangeRequest deleteAssets:#[phAsset]];
}
completionHandler:^(BOOL success, NSError *error)
{
if ((!success) && (error != nil))
{
NSLog(#"Error deleting asset: %#", [error description]);
}
}];
}
}
}
When using the Photos framework, don't forget to link Photos.framework in your target and also import the header in your source file: #import <Photos/Photos.h>
I have a similar problem, and haven't been able to resolve it either. I think its a bug in 8.3 with the AssetsLibrary, and would suggest you submit a bug report to Apple as I have:
Can't edit photo metadata using AssetsLibrary in iOS 8.3 (worked in 8.2)
The user has denied the application access to their media
This explains why you have the error. As far as the system is concerned you don't have access to the photo library.
You need to look at checking the authorization status and requesting if needed as show in the Apple Doc's
You need something like:
if([PHPhotoLibrary authorizationStatus] != PHAuthorizationStatus.PHAuthorizationStatusAuthorized){
[PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status)
{
if (status != PHAuthorizationStatus.PHAuthorizationStatusAuthorized)
{
//Fail
}
else
{
//SetImageData
}
}
}
Related
I am developing a framework in iOS. I have a function in my framework that it gets the most recent image from the Camera Roll by using Photos framework. This function works successfully in most of projects which use my framework. But it crashes on only one project from these projects. I tried several ways to fix this crash, but nothing changed in this crash.
I checked this project settings but I could not find any difference from my project settings. Also I checked the gallery permission in the plist file. Also there is an interesting point. This project uses almost all functions of my library successfully but it also crashes when my library tries to reach UIImagePickerController in this project.
#interface Controller ()
{
UIBarButtonItem *barButtonItem;
}
#property(nonatomic, strong) PHFetchResult *fetchResult;
#property(nonatomic, strong) PHAsset *lastAsset;
#end
// calling this in the main thread
- (void)checkGalleryPermission
{
PHAuthorizationStatus status = [PHPhotoLibrary authorizationStatus];
if (status == PHAuthorizationStatusAuthorized)
{
[self setLastGalleryImageToPhotoGallery];
}
else if (status == PHAuthorizationStatusNotDetermined)
{
[PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status)
{
if (status == PHAuthorizationStatusAuthorized)
{
dispatch_async(dispatch_get_main_queue(), ^{
[self setLastGalleryImageToPhotoGallery];
});
}
}];
}
}
- (void)setLastGalleryImageToPhotoGallery
{
PHFetchOptions *fetchOptions = [[PHFetchOptions alloc] init];
fetchOptions.sortDescriptors = #[[NSSortDescriptor sortDescriptorWithKey:#"creationDate" ascending:YES]];
self.fetchResult = [PHAsset fetchAssetsWithMediaType:PHAssetMediaTypeImage options:fetchOptions];
if (self.fetchResult != nil)
{
self.lastAsset = [self.fetchResult lastObject];
if (self.lastAsset != nil)
{
PHImageRequestOptions *imageRequestOptions = [[PHImageRequestOptions alloc] init];
imageRequestOptions.deliveryMode = PHImageRequestOptionsDeliveryModeFastFormat;
imageRequestOptions.synchronous = YES; // tried NO
imageRequestOptions.version = PHImageRequestOptionsVersionCurrent;
[[PHImageManager defaultManager] requestImageForAsset:self.lastAsset targetSize:CGSizeMake(42.0f, 42.0f) contentMode:PHImageContentModeAspectFill options:imageRequestOptions resultHandler:^(UIImage *result, NSDictionary *info)
{
dispatch_async(dispatch_get_main_queue(), ^{
[self->barButtonItem setImage:[result imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal]];
});
}];
}
}
}
I put logs in the above functions to find where it crashes. And it crashes after the below code. I could not figure out the problem. Is there any restriction in the project setting to reach Camera Roll or is this problem related to thread?
self.fetchResult = [PHAsset fetchAssetsWithMediaType:PHAssetMediaTypeImage options:fetchOptions];
If the same crash happens also using UIImagePickerController there is most likely an issue with the iOS Photo Library on this one device. The iOS Photo Library is a Core-Data database under the hood and can be corrupt. Did you have a look at the crash report. If you see any SQL-/Core-Data issues this would point to database problems.
I am trying to create a collection list in Photos which will have multiple albums.
The code to create the collection list is as follows:
__block NSString * localId;
NSError *createFolderError;
[[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
// Create the folder
PHCollectionListChangeRequest *changeRequest = [PHCollectionListChangeRequest creationRequestForCollectionListWithTitle: #"My Photos"];
localId = [[changeRequest placeholderForCreatedCollectionList] localIdentifier];
} completionHandler:^(BOOL success, NSError * _Nullable error) {
if (!success) {
DebugLog(#"Creating My Photos Folder Failed... error : %#", error.description);
return;
}
if(localId) {
//Do something
}
}];
But, getting error as follows:
Error Domain=NSCocoaErrorDomain Code=-1 "(null)"
Earlier, it was creating folder even after getting the error, but now, I see folder not getting created under Photos application.
Let me know if I am doing anything wrong.
EDIT
The folder is getting created in the Photos app each time, but was not reflecting. When Photos App was killed and relaunched, I can see the folder. But still, why the error is shown, remains a question.
Hi I'm playing with the new photos framework for ios 8.0. I'm trying to delete an array of photos and here is the code:
NSArray *toDeletePhotos = [photos valueForKey:#"asset"];
[[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
[PHAssetChangeRequest deleteAssets:toDeletePhotos];
} completionHandler:^(BOOL success, NSError *error) {
if (success) {
dispatch_async(dispatch_get_main_queue(), ^{
[self refreshPhotosAfterDeleting];
});
}
}];
I tested this on around 8 devices. 6 of them successfully deleted selected photos and 2 of them returned and error that says: Error Domain=NSCocoaErrorDomain Code=-1 "The operation couldn’t be completed. (Cocoa error -1.)" The two devices I tested on are 6+ and 5s.
I couldn't figure out what error it is and wonder anyone could help me with this. Thanks!
so after a while I solved the problem my self.
It turns out that when photos are streamed/synced from other devices, there's no way you can delete them without deleting them on iTunes/iCoud. So I added a filter so no streamed/synced photos are fetched.
For more information please refer to: https://support.apple.com/en-us/HT204120.
Hope this helps!
I want to save all image's from my app with new album(with my app name). so I have use asserts library in my project. it is working good in ios 7 but not in ios8 and later one.With Mistake when user remove album from photos,assert library unable to create new album again with same name in ios8. Any one has solution for this? Thanks
You can try My below Method for Create Album for iOS 7 and iOS 8
#define PHOTO_ALBUM_NAME #"AlbumName Videos"
#pragma mark - Create Album
-(void)createAlbum{
// PHPhotoLibrary_class will only be non-nil on iOS 8.x.x
Class PHPhotoLibrary_class = NSClassFromString(#"PHPhotoLibrary");
if (PHPhotoLibrary_class) {
// iOS 8..x. . code that has to be called dynamically at runtime and will not link on iOS 7.x.x ...
[[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
[PHAssetCollectionChangeRequest creationRequestForAssetCollectionWithTitle:PHOTO_ALBUM_NAME];
} completionHandler:^(BOOL success, NSError *error) {
if (!success) {
NSLog(#"Error creating album: %#", error);
}else{
NSLog(#"Created");
}
}];
}else{
[self.library addAssetsGroupAlbumWithName:PHOTO_ALBUM_NAME resultBlock:^(ALAssetsGroup *group) {
NSLog(#"adding album:'Compressed Videos', success: %s", group.editable ? "YES" : "NO");
if (group.editable == NO) {
}
} failureBlock:^(NSError *error) {
NSLog(#"error adding album");
}];
}}
So I am trying to allow two users to swap files that each has in their Google Drive. That involves knowing the ID of the other person's file and using the API calls to retrieve it. Both files sit in folders that have been shared to anyone/public.
Trouble is when I execute the code below I am finding that each user can only use the downloadUrl corresponding to the file they own - the others return a 404. In this case either "mine" or "theirs" depending on the account I'm logged into.
// _driveService and its authorizer setup elsewhere
// Retrieve the metadata then the actual data
NSString *mine = #"0B4Pba9IBDsR3T1NVTC1XSGJTenc";
NSString *theirs = #"0B4n9OyY8tqWpNlNaN1dUc3FsNG8";
NSString *get = [NSString stringWithFormat:#"https://www.googleapis.com/drive/v2/files/%#",theirs];
[_driveService fetchObjectWithURL:[NSURL URLWithString:get] completionHandler:^
(GTLServiceTicket *ticket, GTLDriveFile *file, NSError *error)
{
if (error != nil)
NSLog(#"Error retrieving metadata: %#", error);
else
{
// Download the actual data
GTMHTTPFetcher *fetcher = [_driveService.fetcherService fetcherWithURLString:file.downloadUrl];
[fetcher beginFetchWithCompletionHandler:^
(NSData *data, NSError *error)
{
if (error != nil)
NSLog(#"Error retrieving actual data: %#", error);
else
{
NSString *content = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(#"Content: %#", content);
}
}];
}
}];
Error retrieving actual data: Error Domain=com.google.HTTPStatus Code=404 "The operation couldn’t be completed. (com.google.HTTPStatus error 404.)"
What am I doing wrong here? If it's a permissions thing, why am I allowed to get the metadata?
Note this is for an iOS app and both files were created and uploaded from the app using the official client API (rev 353).
Hah, so it seems the devil is in the detail I left out of the question. When creating the authorizer the scope I was providing is kGTLAuthScopeDriveFile, which was the default in an example and I forgot all about it when everything else thus far worked fine. Apparently I need to use kGTLAuthScopeDrive instead (the differences are explained here)
The logic seems a bit flawed here though, I mean I don't want access to other files that weren't created with the app, I just want access to a public file somebody else created with the app...