How to get photos from camera roll? - iphone

I tried to use ALAssetLibrary to get albums and photos. This is my code:
void (^assetEnumerator)(struct ALAsset *, NSUInteger, BOOL *) = ^(ALAsset *result, NSUInteger index, BOOL *stop) {
if(result != NULL) {
NSLog(#"See Asset: %#", result);
}
};
void (^assetGroupEnumerator)(struct ALAssetsGroup *, BOOL *) = ^(ALAssetsGroup *group, BOOL *stop) {
if(group != nil) {
[group enumerateAssetsUsingBlock:assetEnumerator];
}
};
ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
[library enumerateGroupsWithTypes:ALAssetsGroupAll
usingBlock:assetGroupEnumerator
failureBlock: ^(NSError *error) {
NSLog(#"Failure");
}];
I'm getting exc_bad_access on : [group enumarateAssetsUsingBlock:assetEnumerator] and the group is not nil.
The strange thing is that this code is working if I create a new project, but in my old project it's not working.
SDK version is iOS 4.3
Tested on iPhoneSimulator 4.3
Can anyone could give me an ideea of what's happening?
Thanks.

As you crash on the one project but not on the other, are you sure the settings and configurations are appropriate?
In particular:
Check that the TARGET_DEPLOYMENT_OS is set to the minimum version the ALAsset framework is available.
Check that you have included all the requested frameworks (even if the linker should warn about this if you forgot to include it)
Moreover, the details of the crash (crashlog, exception details, ...) would be helpful if any.
Also are you sure the ALAssetLibrary isn't released before the enumeration (which is probably done asynchnously) ends? There is no release in your code in your question but maybe there is one in your real code?
AFAIK, enumerateGroupsWithTypes: executes its block on a secondary thread in an asynchrnous way (see this other question on SO), so that's probably your problem (you are trying to use a group that has been released from memory since you start your enumeration, you have to be sure the ALAssetLibrary is still in memory until the enumeration is done)

Related

how to prevent ALAssetsLibrary to get video thumbnail images with liabrary images?

I'm using the following code to access all ALAssetsLibrary images but the ALAssetsLibrary is giving me the saved video thumbnail images with the saved images from ALAssetsLibrary. how can i prevent this using the code so that i can get only saved images?
//Method to get all images from devices library
- (NSMutableArray*)getAllImagesFromLibrary
{
//get all images from image library
void (^assetEnumerator)(ALAsset *, NSUInteger, BOOL *) = ^(ALAsset *result, NSUInteger index, BOOL *stop) {
if(result != NULL) {
//Insert objects into array
[self.arrOfAllImages addObject:result];
}
};
void (^assetGroupEnumerator)(ALAssetsGroup *, BOOL *) = ^(ALAssetsGroup *group, BOOL *stop) {
if(group != nil) {
[group enumerateAssetsUsingBlock:assetEnumerator];
}
};
//NSMutableArray allacation
NSMutableArray *arrOfAllImage = [[NSMutableArray alloc] init];
static dispatch_once_t pred = 0;
static ALAssetsLibrary *library = nil;
dispatch_once(&pred, ^{
library = [[ALAssetsLibrary alloc] init];
});
[library enumerateGroupsWithTypes:ALAssetsGroupSavedPhotos
usingBlock:assetGroupEnumerator
failureBlock: ^(NSError *error) {
NSLog(#"Failure");
}];
return arrOfAllImage;
}
Set a filter before you enumerate:
[group setAssetsFilter: [ALAssetsFilter allPhotos]];
Check your result, If it will image the add in array otherwise not
void (^assetEnumerator)(ALAsset *, NSUInteger, BOOL *) = ^(ALAsset *result, NSUInteger index, BOOL *stop) {
if(result != NULL) {
if ([[result valueForProperty:ALAssetPropertyType] isEqualToString:ALAssetTypePhoto])
{
//Insert objects into array
[self.arrOfAllImages addObject:result];
}
}
};
You can mention many types of Asset through ALAssetsGroupType
They are
ALAssetsGroupLibrary
ALAssetsGroupAlbum
ALAssetsGroupEvent
ALAssetsGroupFaces
ALAssetsGroupSavedPhotos
ALAssetsGroupPhotoStream
ALAssetsGroupAll
1
ALAssetsGroupLibrary
The Library group that includes all assets that are synced from
iTunes.
Available in iOS 4.0 and later.
Declared in ALAssetsLibrary.h.
2
ALAssetsGroupAlbum
All the albums created on the device or synced from iTunes, not
including Photo Stream or Shared Streams
Available in iOS 4.0 and later.
Declared in ALAssetsLibrary.h.
3
ALAssetsGroupEvent
All events, including those created during Camera Connection Kit
import.
Available in iOS 4.0 and later.
Declared in ALAssetsLibrary.h.
4
ALAssetsGroupFaces
All the faces albums synced from iTunes.
Available in iOS 4.0 and later.
Declared in ALAssetsLibrary.h.
5
ALAssetsGroupSavedPhotos
All the photos in the Camera Roll.
Available in iOS 4.0 and later.
Declared in ALAssetsLibrary.h.
6
**ALAssetsGroupPhotoStream**
The PhotoStream album.
In iOS 6.0 and later, this also includes Shared Streams.
Available in iOS 5.0 and later.
Declared in `ALAssetsLibrary.h`.
7
ALAssetsGroupAll
The same as ORing together all the group types except for
ALAssetsGroupLibrary.
Available in iOS 4.0 and later.
Declared in ALAssetsLibrary.h.
You can see more details developer.apple
Example:
[library enumerateGroupsWithTypes:ALAssetsGroupSavedPhotos
usingBlock:assetGroupEnumerator
failureBlock: ^(NSError *error) {
NSLog(#"Failure");
}];

Request access to photo library during app launch

I'm working on an app that takes pictures automatically during certain events and saves them directly to the photo library. Unfortunately the user might not always be looking at their phone when this is running and the first time a picture is taken it asks for permission to access photos.
Is there a way I can force this request during launch and get it out of the way?
Thanks
Yes. You need to request access to the library.
Simply use this code in AppDelegate's didFinishLaunchingWithOptions
ALAssetsLibraryGroupsEnumerationResultsBlock assetGroupEnumerator =
^(ALAssetsGroup *assetGroup, BOOL *stop) {
if (assetGroup != nil) {
// do somthing
}
};
ALAssetsLibraryAccessFailureBlock assetFailureBlock = ^(NSError *error) {
LogError(#"Error enumerating photos: %#",[error description]);
};
NSUInteger groupTypes = ALAssetsGroupAll;
[library enumerateGroupsWithTypes:groupTypes usingBlock:assetGroupEnumerator failureBlock:assetFailureBlock];

ALAssetsLibrary delete ALAssetsGroup / ALAsset

I have created "photos album" from my App, using IOS AssetsLibrary.
Reading ALAssetsLibrary,ALAssetsGroup and ALAsset documentations, i have seen methods to "addAsset","addAssetsGroupAlbumWithName".
Is there a way to delete PROGRAMMATICALLY my ALAssetsGroup and ALAsset.
(the property 'editable' suppose to be TRUE because i create this data).
You can only delete the ALAsset which is created by your app with document API [ALAsset setImageData:metadata:completionBlock:] (But I have not found any API to delete a ALAssetGroup).
1). Add an image "photo.jpg" to your project
2). Save an image to asset library:
ALAssetsLibrary *lib = [ALAssetsLibrary new];
UIImage *image = [UIImage imageNamed:#"photo.jpg"];
[lib writeImageToSavedPhotosAlbum:image.CGImage metadata:#{} completionBlock:^(NSURL *assetURL, NSError *error) {
NSLog(#"Write image %# to asset library. (Error %#)", assetURL, error);
}];
3). Go to default gallery, you will find photo.jpg in your "Saved Photos" album.
4). Delete this image from asset library:
ALAssetsLibrary *lib = [ALAssetsLibrary new];
[lib enumerateGroupsWithTypes:ALAssetsGroupSavedPhotos usingBlock:^(ALAssetsGroup *group, BOOL *stop) {
[group enumerateAssetsUsingBlock:^(ALAsset *asset, NSUInteger index, BOOL *stop) {
if(asset.isEditable) {
[asset setImageData:nil metadata:nil completionBlock:^(NSURL *assetURL, NSError *error) {
NSLog(#"Asset url %# should be deleted. (Error %#)", assetURL, error);
}];
}
}];
} failureBlock:^(NSError *error) {
}];
5). Go to default gallery, you will find photo.jpg has already been deleted.
This is not possible using any documented API. Only the photos app can delete Albums. If you want this feature to be added to iOS, I would fill a feature request at https://feedbackassistant.apple.com/.
in ios8 deleting photos might be possible using the Photos Framework
Please check the documentation of Photos Framework
For deleting assets refer to PHAssetChangeRequest
+ (void)deleteAssets:(id<NSFastEnumeration>)assets
where assets is an array of PHAsset objects to be deleted.
For deleting collections refer to PHAssetCollectionChangeRequest
+ (void)deleteAssetCollections:(id<NSFastEnumeration>)assetCollections
https://developer.apple.com/library/prerelease/ios/documentation/Photos/Reference/PHAssetChangeRequest_Class/index.html#//apple_ref/occ/clm/PHAssetChangeRequest/deleteAssets:
As Ted said, this is now possible in iOS 8 using the Photos service. It's pretty clean actually. You need to submit a change request to the photolibrary. Here's an example.
[[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
[PHAssetChangeRequest deleteAssets:arrayOfPHAssets];
} completionHandler:^(BOOL success, NSError *error) {
NSLog(#"Finished deleting asset. %#", (success ? #"Success." : error));
}];
Make sure you've imported Photos, and gotten authorization from the user. (Which you probably did to show the image already)
PHAssetchangeRequest - deleteAssets
https://developer.apple.com/library/prerelease/ios/documentation/Photos/Reference/PHAssetChangeRequest_Class/index.html#//apple_ref/occ/clm/PHAssetChangeRequest/deleteAssets:
PHPhotoLibrary Class - authorizationStatus
https://developer.apple.com/library/ios/documentation/Photos/Reference/PHPhotoLibrary_Class/#//apple_ref/occ/clm/PHPhotoLibrary/authorizationStatus
evanchin is correct. Further more, if you want to do this in Xamarin.iOS (aka monotouch):
var lib = new ALAssetsLibrary();
lib.Enumerate(ALAssetsGroupType.All, (ALAssetsGroup group, ref bool libStop) =>
{
if (group == null)
{
return;
}
group.Enumerate((ALAsset asset, int index, ref bool groupStop) =>
{
if (asset != null && asset.Editable)
{
asset.SetImageDataAsync(new NSData(IntPtr.Zero), new NSDictionary(IntPtr.Zero));
}
});
}, error => { });
This code will delete all images that your app added to the ALAssetsLibrary.
You may delete any asset in the library using documented API ONLY.
over writing the [ALAsset isEditable] function:
#implementation ALAsset(DELETE)
-(BOOL)isEditable{
return YES;
}
#end
like evanchin said, delete the asset:
ALAssetsLibrary *lib = [ALAssetsLibrary new];
[lib enumerateGroupsWithTypes:ALAssetsGroupSavedPhotos
usingBlock:^(ALAssetsGroup *group, BOOL *stop) {
[group enumerateAssetsUsingBlock:^(ALAsset *asset, NSUInteger index, BOOL *stop) {
if(asset.isEditable) {
[asset setImageData:nil
metadata:nil
completionBlock:^(NSURL *assetURL, NSError *error) {
NSLog(#"Asset url %# should be deleted. (Error %#)", assetURL, error);
}];
}
}];
} failureBlock:^(NSError *error) {
}];

Iphone: unable to show photos using AlAssetsLibrary

I currently sending ipa to friends for testing. Funny thing is, one of my tester able view her photos stored on her phone which was running IOS 5 using iPhone 4.
Another 2 testers: one has iPhone 4 (IOS 4.3.3) , and iPhone 3GS (IOS 5.0.1) both of them can't see photos stored on their phone.
These are the code I have used:
ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
void (^assetEnumerator)(ALAsset *, NSUInteger, BOOL *) = ^(ALAsset *result, NSUInteger index, BOOL *stop) {
if(result != NULL) {
//NSLog(#"See Asset: %#", #"ggg");
[assets addObject:result];
}
};
NSLog(#"location = %i length = %i ", range->location, range->length );
void (^assetGroupEnumerator)(ALAssetsGroup *, BOOL *) = ^(ALAssetsGroup *group, BOOL *stop) {
if(group != nil) {
NSRange *datarange = malloc(sizeof(NSRange));
range->total = [group numberOfAssets];
datarange->location = [group numberOfAssets] - range->location - range->length;
datarange->length = range->length;
NSLog(#" total = %i", range->total);
int location = [group numberOfAssets] - range->location - range->length;
if (location < 0)
{
datarange->location = 0;
datarange->length = [group numberOfAssets] - range->location;
}
NSIndexSet *indexset = [ [NSIndexSet alloc] initWithIndexesInRange:*datarange];
[group enumerateAssetsAtIndexes:indexset options:NULL
usingBlock:assetEnumerator];
[indexset release];
free(datarange);
[self loadAssetToScrollView:assets];
}
};
[assets release];
assets = [[NSMutableArray alloc] init];
[library enumerateGroupsWithTypes:ALAssetsGroupSavedPhotos
usingBlock:assetGroupEnumerator
failureBlock: ^(NSError *error) {
NSLog(#"Failure");
}];
[library release];
I saw somebody say about asynchronous thing in some other threads but don't know is it the case. He say put dispatch_async in the enumerate group block.
Does anyone know what is wrong.
Additionally, one of tester with iOS 4.3.3 can show his photos after enabling location services under General->Setting. Why we have to enable it? Can we enabled it on code since it will be quite disturbing to the user who using our application.
Also on iOS 5.x you must retain your ALAssetsLibrary instance so long as you need to work with the collected assets. When you release your ALAssetsLibrary instance like in your code just after calling [library enumerateGroupsWithTypes:…] all the collected assets will be invalid.
See also the ALAssetsLibrary doc - overview:
"… The lifetimes of objects you get back from a library instance are tied to the lifetime of the library instance. …"
Yes, it is incredibly frustrating, but that is how it is, and you cannot enable location services in code (that is a good thing though).
I would move the first block ^assetGroupEnumerator to the heap by [[<#block#> copy] autorelease]. Why? Because this block would be autoreleased by the runloop, if there are many assets need to be enumerated through.
One more thing: don't use [self loadAssetToScrollView:assets]; inside the block but get the weak reference of self before the block like this:
__block YourExampleClassInstance *weakSelf = self;
and further use this weakSelf instance inside the block:
[weakSelf loadAssetToScrollView:assets];
void (^assetGroupEnumerator)… = ^(ALAssetsGroup *group, BOOL *stop) {
…
};
Why? To avoid retain cycles.

is there any way to get all photos from gallery prophetically using objective-c code?

i have to fetch all photos from the iphone gallery without open the imagepickercontroller. if any have any idea or reference then post here and help me to complete my task.
Thanks in advance
Ravi
You can use ALAssetsLibrary for that. Keep in mind that users have to grant your application access to the location services to be able to "read" the items in your library. Try this piece of code and let me know if it works:
ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
ALAssetsLibraryGroupsEnumerationResultsBlock successBlock = ^(ALAssetsGroup *group, BOOL *stop) {
if (group != nil) {
[group enumerateAssetsUsingBlock:^(ALAsset *result, NSUInteger index, BOOL *stop) {
if (result != nil) {
// do something with your asset
}
}];
}
};
ALAssetsLibraryAccessFailureBlock failureBlock = ^(NSError *error) {
NSLog(#"Could not enumarate assets. Reason: %#", error);
};
[library enumerateGroupsWithTypes:ALAssetsGroupAll usingBlock:successBlock failureBlock:failureBlock];
[library release];
You can also read this for more details. Also, don't forget to add #import <AssetsLibrary/AssetsLibrary.h> in your .h file and link the AssetsLibrary.framework to your project before.
Let me know if that helps!