assetsLibrary a simple bug? - objective-c

I am really lost .
why i get NSLog twice for each UIImage ?
//------ get the images from the camera roll ----------
assets=[[NSMutableArray alloc]init];
NSMutableArray *cameraRollPictures=[[NSMutableArray alloc]init];
ALAssetsLibrary *assetsLibrary = [[ALAssetsLibrary alloc] init];
[assetsLibrary enumerateGroupsWithTypes:ALAssetsGroupSavedPhotos usingBlock:^(ALAssetsGroup *group, BOOL *stop)
{
NSInteger numberOfAssets = [group numberOfAssets];
NSLog(#"NUM OF IMAGES:%d",numberOfAssets);
if (numberOfAssets > 0)
{
for (int i = 0; i <= numberOfAssets-1; i++)
{
[group enumerateAssetsAtIndexes:[NSIndexSet indexSetWithIndex:i] options:0 usingBlock:^(ALAsset *result, NSUInteger index, BOOL *stop)
{
UIImage *thumbnail = [UIImage imageWithCGImage:[result thumbnail]];
[assets addObject:thumbnail];
NSLog(#"theObject!!!! -- (%d) %#",i,thumbnail);
//******* for each i its here twice !! ********
}];
}
}

For some reason, enumerateAssetsAtIndexes (and enumerateAssetsUsingBlock) do an additional invocation of the block with result == nil and index == NSNotFound at the end of the enumeration. This becomes obvious if you change the NSLog() to
NSLog(#"i=%d, index=%ld, result=%#", i, (unsigned long)index, result);
Then you will get the output
NUM OF IMAGES:2
i=0, index=0, result=ALAsset - Type:Photo, URLs:assets-library://asset/asset.PNG?id=...
i=0, index=2147483647, result=(null)
i=1, index=1, result=ALAsset - Type:Photo, URLs:assets-library://asset/asset.PNG?id=...
i=1, index=2147483647, result=(null)
Therefore you have to check the value of result and ignore a nil value:
for (int i = 0; i <= numberOfAssets-1; i++) {
[group enumerateAssetsAtIndexes:[NSIndexSet indexSetWithIndex:i] options:0 usingBlock:^(ALAsset *result, NSUInteger index, BOOL *stop)
{
if (result != nil) {
UIImage *thumbnail = [UIImage imageWithCGImage:[result thumbnail]];
[assets addObject:thumbnail];
}
}];
}
Note that you can simplify the enumeration to
[group enumerateAssetsUsingBlock:^(ALAsset *result, NSUInteger index, BOOL *stop) {
if (result != nil) {
UIImage *thumbnail = [UIImage imageWithCGImage:[result thumbnail]];
[assets addObject:thumbnail];
}
}];

Related

How to access smart folder from gallery using ALAsset

I am making an app where I want to get the list of all albums name from gallery including smart folders(favorites, screenshots. this is an old app where we have used ALAsset in order to access the gallery in our app.
Is there any way through which we can access smart folders as well using ALAssetLibrary?
This code is help.
#import <AssetsLibrary/AssetsLibrary.h>
#property (nonatomic, strong) ALAssetsLibrary *_assetsLibrary;
- (ALAssetsLibrary *)defaultAssetsLibrary {
static dispatch_once_t pred = 0;
static ALAssetsLibrary *library = nil;
dispatch_once(&pred, ^{
library = [[ALAssetsLibrary alloc] init];
});
return library;
}
-(void) getgalleryPic
{
if (self.photos == nil) {
self.photos = [[NSMutableArray alloc] init];
}else
{
[self.photos removeAllObjects];
}
PHAuthorizationStatus status = [PHPhotoLibrary authorizationStatus];
if (status == PHAuthorizationStatusAuthorized) {
// Access has been granted.
NSMutableArray *collector = [[NSMutableArray alloc] initWithCapacity:0];
ALAssetsLibrary *library = [self defaultAssetsLibrary];
[library enumerateGroupsWithTypes:ALAssetsGroupAll
usingBlock:^(ALAssetsGroup *group, BOOL *stop)
{
[group enumerateAssetsUsingBlock:^(ALAsset *asset, NSUInteger index, BOOL *stop)
{
if (asset) {
[collector addObject:asset];
}else
{
self.photos = [[[collector reverseObjectEnumerator] allObjects] mutableCopy];
NSLog(#"photo lenght %lu",(unsigned long)[self.photos count]);
[_collectionVW reloadData];
}
}];
}
failureBlock:^(NSError *error) { NSLog(#"Boom!!!");}
];
}
else if (status == PHAuthorizationStatusDenied) {
// Access has been denied.
}
else if (status == PHAuthorizationStatusNotDetermined) {
// Access has not been determined.
[PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) {
if (status == PHAuthorizationStatusAuthorized) {
// Access has been granted.
NSMutableArray *collector = [[NSMutableArray alloc] initWithCapacity:0];
ALAssetsLibrary *library = [self defaultAssetsLibrary];
[library enumerateGroupsWithTypes:ALAssetsGroupAll
usingBlock:^(ALAssetsGroup *group, BOOL *stop)
{
[group enumerateAssetsUsingBlock:^(ALAsset *asset, NSUInteger index, BOOL *stop)
{
if (asset) {
[collector addObject:asset];
}else
{
self.photos = [[[collector reverseObjectEnumerator] allObjects] mutableCopy];
NSLog(#"photo lenght %lu",(unsigned long)[self.photos count]);
[_collectionVW reloadData];
}
}];
}
failureBlock:^(NSError *error) { NSLog(#"Boom!!!");}
];
}
else {
// Access has been denied.
}
}];
} else if (status == PHAuthorizationStatusRestricted) {
// Restricted access - normally won't happen.
}
}

Updating PSTCollectionView contents while loading photos

I'm using PSTCollectionView class to load the photos from iPhone camera roll. I want the photos to appear while they're loaded though, not wait until everything is read. My code looks like this:
-(void) loadAssetGroups {
void (^assetGroupEnumerator)
(ALAssetsGroup *, BOOL *) = ^(ALAssetsGroup *group, BOOL *stop) {
NSLog(#"group....%#",[group valueForProperty:ALAssetsGroupPropertyName]);
[self loadAssetForGroup:group];
}
};
void (^assetGroupEnumberatorFailure)(NSError *) = ^(NSError *error) {
NSLog(#"A problem occured. Error: %#", error.localizedDescription);
};
[[ImagePickerViewController defaultAssetsLibrary] enumerateGroupsWithTypes:ALAssetsGroupAll
usingBlock:assetGroupEnumerator
failureBlock:assetGroupEnumberatorFailure];
}
-(void) loadAssetForGroup:(ALAssetsGroup*)group {
ALAssetsFilter *filter = [ALAssetsFilter allPhotos];
[group setAssetsFilter:filter];
__block NSMutableArray *indexes = [NSMutableArray arrayWithCapacity:0];
[group enumerateAssetsWithOptions:NSEnumerationReverse usingBlock:^(ALAsset *result, NSUInteger index, BOOL *stop) {
if (result == nil)
{
return;
}
if (![self.allPhotos containsObject:result]) {
[self.assets setValue:result forKey:[result valueForProperty:ALAssetPropertyURLs]];
[self.allPhotos addObject:result];
[indexes addObject:[NSIndexPath indexPathForItem:[self.allPhotos count]-1 inSection:0]];
[self.collectionView performSelectorOnMainThread:#selector(insertItemsAtIndexPaths:) withObject:[NSArray arrayWithObject:[NSIndexPath indexPathForItem:self.allPhotos.count-1 inSection:0]] waitUntilDone:NO];
}
}];
}
From the console I see that collectionView is calling its dataSource method cellForItemAtIndexPath for the first few objects (that would be visible on the screen) but I need to wait for all photos to be read until I see the collectionView refreshed.
Is there a way to have it running more "on the go"?

Get camera roll images and their EXIF data?

I figured out how to get all the user's images in the camera roll using the AssestsLibrary:
- (void)updateLastPhotoThumbnail {
ALAssetsLibrary *assetsLibrary = [[ALAssetsLibrary alloc] init];
[assetsLibrary enumerateGroupsWithTypes:ALAssetsGroupSavedPhotos usingBlock:^(ALAssetsGroup *group, BOOL *stop) {
NSInteger numberOfAssets = [group numberOfAssets];
if (numberOfAssets > 0) {
NSLog(#"numberOfPictures: %d",numberOfAssets);
//NSInteger lastIndex = numberOfAssets - 1;
int i = 0;
for (i = 0; i <= numberOfAssets-1; i++) {
[group enumerateAssetsAtIndexes:[NSIndexSet indexSetWithIndex:i] options:0 usingBlock:^(ALAsset *result, NSUInteger index, BOOL *stop) {
UIImage *thumbnail = [UIImage imageWithCGImage:[result thumbnail]];
NSLog(#"theObject!!!! -- (%d) %#",i,thumbnail);
[cameraRollPictures addObject:thumbnail];
}];
}
}
} failureBlock:^(NSError *error) {
NSLog(#"error: %#", error);
}];
}
I successfully created the array of UIIMages, but how could I get EXIF data from the UIImages using this snippet I have?
PS: I've looked at this http://code.google.com/p/iphone-exif, but I cannot get it to build without errors.
You can't get metadata from UIImage objects.
But you can query an ALasset object for metadata:
NSDictionary *metadata = [[result defaultRepresentation] metadata];
Chefs,
Hendrik

Create an array of UIImages from camera roll

I would like to get all of the images from the camera roll and create an array of UIImages from them.
I have been trying to figure out how to do this for about a day now and I've gotten nowhere. I can't seem to figure out how to retrieve only items from the Camera Roll. It appears that all of the samples that I've seen all enumerate over all of the photo albums. I might be wrong about that though.
Any help would be appreciated. Thanks!
Have you tried ALAssetsLibrary? like this:
assets = [[NSMutableArray array] init]; // Prepare array to have retrieved images by Assets Library.
void (^assetEnumerator)(ALAsset *, NSUInteger, BOOL *) = ^(ALAsset *asset, NSUInteger index, BOOL *stop) {
if(asset != NULL) {
[assets addObject:asset];
dispatch_async(dispatch_get_main_queue(), ^{
[self insertArray];
});
}
};
void (^assetGroupEnumerator)(ALAssetsGroup *, BOOL *) = ^(ALAssetsGroup *group, BOOL *stop) {
if(group != nil) {
[group enumerateAssetsUsingBlock:assetEnumerator];
}
};
// Create instance of the Assets Library.
library = [[ALAssetsLibrary alloc] init];
[library enumerateGroupsWithTypes:ALAssetsGroupSavedPhotos // Retrieve the images saved in the Camera roll.
usingBlock:assetGroupEnumerator
failureBlock: ^(NSError *error) {
NSLog(#"Failed.");
}];
that'll nab them. then do this to render them (this is wicked hacky. you'll want to import them as needed and not all at once like this, or you'll run into memory issues and crash)
-(void) insertArray {
int i = assetCount++;
if (i>20) {
return;
}
ALAssetRepresentation *rep = [[assets objectAtIndex:i] defaultRepresentation];
CGImageRef iref = [rep fullResolutionImage];
CGSize cSize = CGSizeMake(75,75);
UIImage *largeimage = [UIImage imageWithCGImage:iref];
UIImage *resizedimage = (UIImage *)[largeimage resizedImage:cSize interpolationQuality:kCGInterpolationHigh];
UIImageView *newView = [[UIImageView alloc] initWithImage:resizedimage];
if((i>0)&&(i%4 == 0)){
rowCount++;
}
colCount = i%4;
newView.frame = CGRectMake(4+(colCount*(75+4)), 4+(rowCount*(75+4)), 75, 75);
[sv addSubview:newView];
[sv setContentSize:CGSizeMake(320, 85+(rowCount*(75+4)))];
NSLog(#"sv frame size is %# and i is %i", NSStringFromCGRect(sv.frame), i);
}

ios assets not work on ios5

here is my code:
[library enumerateGroupsWithTypes:ALAssetsGroupAlbum
usingBlock:assetGroupEnumerator
failureBlock: ^(NSError *error) {
NSLog(#"Failure");
}];
my previous code is this:
assets = [[NSMutableArray alloc] init];
void (^assetEnumerator)( ALAsset *, NSUInteger, BOOL *) = ^(ALAsset *result, NSUInteger index, BOOL *stop) {
if(result != NULL) {
NSLog(#"See Asset: %#", result);
[assets addObject:result];
}
};
void (^assetGroupEnumerator)( ALAssetsGroup *, BOOL *) = ^(ALAssetsGroup *group, BOOL *stop) {
if(group != nil) {
[group enumerateAssetsUsingBlock:assetEnumerator];
}
[self.tableView reloadData];
};
ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
and with my phone (ios5) doesn't work, can't go to the assetGroupEnumerator...
also in the simulator, the same thing....
any ideas?
thanks in advance
Are you releasing your ALAssetsLibrary before you are done displaying the assets? You need to retain the library throughout the lifetime of the groups and assets you are using.