Thanks for making this open, I think its highly useful keeping this cloned to the appearance of the existing ImagePickerController.
So far I’ve successfully run this in the simulator on the 4.2 beta SDK. The initial app doesn’t seem to run on my iPad with the 4.2 beta on it currently though, The initial ELCImagePickerDemoViewController doesn’t display the button. No idea why at the moment but if I have time next week to work with this a bit more I’ll let you know as I will try to integrate this into my own app and see how it goes later in the week.
One question I have is how does the memory get reclaimed in the case of the following method
-(void)selectedAssets:(NSArray*)_assets {
I’m relatively new to Obj-C and Cocoa touch from Java development so some memory handling remains for me to fully understand. Given that you allocate the member returnArray and then pass it via the delegate method does this mean the delegate needs to know that it has to release the returnArray itself? Or is there some other way the memory is released. I’d assume ( possibly incorrectly) that the ELCImagePickerController class would retain the NSMutableArray.
Also, I haven’t yet implemented a delegate and I’m fascinated by this particular pattern.
@Sam
I dont know about your thumbnail issue but I did notice that when using the ELCImagePickerController that I would not get the full resolution image. I have found how to change this and will share for you or others:
This is great and thank you for making it available. I have question, I would like to show a UIView after the users selects their images. If a user selects 20 or more it appears that the app locks up, it doesnt it just looks that way. So I want to show a sort of “Please Wait” so the user sees that the app is busy. How is the best way to implement this?
I basically had to show a sub view that is semi-transparent, remove the back button and done button.
Next I had to show my sub view when the dismiss button was clicked in -(void)selectedAssets:(NSArray*)_assets in the AssetTablePicker implementation.
Then I had to move -(void)selectedAssets:(NSArray*)_assets in ELCImagePickerController implementation to a background thread so the ui doesn’t lock up.
First I would like to thank for this great tutorial.
I come across one problem with this, when we have more number of images in image library, the application will crash. I think, because of putting images in array(memory issue). Is it possible to save images in database(sqlite, local memory)and then show in scroll view.
It looks like you are trying to pass a array of images to the picker. That is not how it works. ELCImagePickerController allows you to pick images, then passes them back via the delegate to where ever you initiated it from.
Hi, firstly thank you very much for the code. The code runs perfectly well in Simulator 4.1 but when I try 4.0 or 4.2 it gets stuck on the Loading screen and it gives me the following comment on the GDB
2010-11-16 16:37:27.514 ELCImagePickerDemo[49819:6b03] A problem occured
Its from this line in the code.
ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
[library enumerateGroupsWithTypes:ALAssetsGroupAll
usingBlock:assetGroupEnumerator
failureBlock:^(NSError *error) {
NSLog(@"A problem occured");
}];
Somehow I am not able to figure out what is the problem, I have added the Asset Lib framework and everything. Please help.
Great article. Just having some problems with the source code provided. Using simulator 4.2. and the latest xcode (downloaded last night), It builds fine, loads the album viewer, but when it loads up the images in the album, and then I select them, all the images just disappear. When I try clicking anywhere else it just crashes.
Console doesn’t spit out anything either which is annoying because I cant see whats going wrong.
I’ve found a problem with the code that prepares the group table. A couple of subtle problems are happening that I don’t yet understand. However, if you remove the NSLog statement from the closure then two problems appear.
ie : remove the line
NSLog(@”Number of assets in group=%d”, [group numberOfAssets]);
from the prepareImages method in the group level picker
1. The count numbers for number of assets may not appear in the subsequent code that formats the table rows. Sometimes the count is incorrectly stated as zero.
2. If the user does not create an albums in the photo library but just syncs their images with the library as a whole, then when you pick the ‘PhotoLibrary’ group or the ‘Shared Photos’ group (these are the only ones which are visible in this case) then the user will see no photos found.
I’ve replaced the NSLog line with the following
int count = [group numberOfAssets]; //ignore the warning from not using ‘count’
And the code still works with this, so it looks as though there is something subtle going on here with how the closure is executing. I’ve no idea if this is a bug with the AssetsLibrary, but its certainly worth looking at as it could cause a serious problem with an app.
Trying to get this to work so far so good however my “DONE” button is not appearing when your in the picker it shows the cancel fading out but then fading back in it doesnt change to done so i cant really chose any images. Where do you change the nav bar from cancel to done?
When I run it, it seems that the orientation of the image gets lost. When I check the imageOrientation that gets saved in the dictionary, it also returns:
Thanks for making this. This is saving me time instead of having to roll my own.
With that said, there are several places in this code with glaring memory leaks. I have already forked and committed a fix for one that I have submitted a pull request for. There are others that I’ve discovered that could’ve been avoided with an autorelease call but are much more deeply rooted, and I am, as of right now, unsure of what consequences might result in fixing them.
I tried your sample code on several iPhones and it’s working only if there are not so many pictures stored on the device, once a folder has more then 200 images there is a delay and its shows loading for a few seconds.
However, I have one iPhone 4 with more then 800 images in several folders and it doesn’t even go past the “loading” stage.
I have one app called ” Stash Pro” (hedonic software) and they are able to open the photo library without any delay (even with 800 images) and you can import several pictures or even the complete folder.
Did they use a modified version of this script ? Or does anyone know how they made it ?
It is not working on my iPhone 3GS with iOS4.2.1. It worked on the simulator but it seems that it’s not able to find the photo directory in the device. The behaviour is similar to no photo in the simulator. It said “Loading…”
Thanks a lot for making this library available! Unfortunately I have the same issue as CodeBear. On both my 4.2.1 developer phones and also on my 4.3beta iPad the assetGroupEnumerator does not work. The last output in the console is:
sandboxd[944] : ELCImagePickerDe(942) deny file-write-data /private/var/mobile/Media/PhotoData
It looks like the system is keeping the app from accessing the album data (which indeed is outside the app sandbox). I read through Apple’s documentation on Assets and tried various stuff but I always end up with this error. Does anyone have an idea what the issue might be? Has anyone probably tested the code on a non-developer iPhone running 4.2.1 (with an ad hoc certificate for example or with an app from the app store)?
At the moment I’m really a bit lost with this problem. Of course I understand it’s not an issue with ELCImagePickerController, but rather with the iPhone 4.2.1 API and/or system.
Ok, looks like I found the problem. It seems that you can only make calls to the ALAssetsLibrary in the app’s main thread in 4.2 (or probably even earlier.
I changed the following line in the implementation of ELCImagePickerController.
i buildup this code to iPad.i am using IOS SDK 4.2.When i’m pressing the “Launch ELC Image Picker Controller Button” it shows only empty table still the navigation bar holds the message “Loading..”.But in simulator it works fine.Please help to short it out.
i am new in iphone. i want to develop the webservice application. i am developing the application for the welcome view and it is reading the message from the webservice xml file .i am puting the code in the -viewdidload function but it is displaying the message.
30 Comments
Thanks for making this open, I think its highly useful keeping this cloned to the appearance of the existing ImagePickerController.
So far I’ve successfully run this in the simulator on the 4.2 beta SDK. The initial app doesn’t seem to run on my iPad with the 4.2 beta on it currently though, The initial ELCImagePickerDemoViewController doesn’t display the button. No idea why at the moment but if I have time next week to work with this a bit more I’ll let you know as I will try to integrate this into my own app and see how it goes later in the week.
One question I have is how does the memory get reclaimed in the case of the following method
-(void)selectedAssets:(NSArray*)_assets {
NSMutableArray *returnArray = [[NSMutableArray alloc] init];
for(ALAsset *asset in _assets) {
NSMutableDictionary *workingDictionary = [[NSMutableDictionary alloc] init];
[workingDictionary setObject:[asset valueForProperty:ALAssetPropertyType] forKey:@”UIImagePickerControllerMediaType”];
[workingDictionary setObject:[UIImage imageWithCGImage:[[asset defaultRepresentation] fullScreenImage]] forKey:@”UIImagePickerControllerOriginalImage”];
[workingDictionary setObject:[[asset valueForProperty:ALAssetPropertyURLs] valueForKey:[[[asset valueForProperty:ALAssetPropertyURLs] allKeys] objectAtIndex:0]] forKey:@”UIImagePickerControllerReferenceURL”];
[returnArray addObject:workingDictionary];
[workingDictionary release];
}
if([delegate respondsToSelector:@selector(elcImagePickerController:didFinishPickingMediaWithInfo:)]) {
[delegate performSelector:@selector(elcImagePickerController:didFinishPickingMediaWithInfo:) withObject:self withObject:[NSArray arrayWithArray:returnArray]];
}
I’m relatively new to Obj-C and Cocoa touch from Java development so some memory handling remains for me to fully understand. Given that you allocate the member returnArray and then pass it via the delegate method does this mean the delegate needs to know that it has to release the returnArray itself? Or is there some other way the memory is released. I’d assume ( possibly incorrectly) that the ELCImagePickerController class would retain the NSMutableArray.
Also, I haven’t yet implemented a delegate and I’m fascinated by this particular pattern.
if([delegate respondsToSelector:@selector(elcImagePickerController:didFinishPickingMediaWithInfo:)]) {
[delegate performSelector:@selector(elcImagePickerController:didFinishPickingMediaWithInfo:) withObject:self withObject:[NSArray arrayWithArray:returnArray]];
As I have no idea to start with the implementation of delegates in Obj-c this is very instructional.
PS: Although your source is open it is copyrighted and I can’t see any information about licensing. Do you have any information about this?
Oops, just seen the MIT license! Ignore previous.
Hello,
I found a major bug in ur app while syncing the photos.I have also made the slideshow using AssetsLibrary and facing the same problem.
Just sync some new photos using itunes and try to acess those photos,only thumbail wd be shown and not the fullscreen/fullres images.
Pls let me know if you have any solution to this.
thanks
@Sam
I dont know about your thumbnail issue but I did notice that when using the ELCImagePickerController that I would not get the full resolution image. I have found how to change this and will share for you or others:
Line #43 in ELCImagePickerController.m
From:
[workingDictionary setObject:[UIImage imageWithCGImage:[[asset defaultRepresentation] fullScreenImage]] forKey:@”UIImagePickerControllerOriginalImage”];
To:
[workingDictionary setObject:[UIImage imageWithCGImage:[[asset defaultRepresentation] fullResolutionImage]] forKey:@”UIImagePickerControllerOriginalImage”];
Any ideas how to implement selection of all the images from the AssetTablePicker..?
This is great and thank you for making it available. I have question, I would like to show a UIView after the users selects their images. If a user selects 20 or more it appears that the app locks up, it doesnt it just looks that way. So I want to show a sort of “Please Wait” so the user sees that the app is busy. How is the best way to implement this?
Thanks,
Albert C.
I figured it out on my own.
I basically had to show a sub view that is semi-transparent, remove the back button and done button.
Next I had to show my sub view when the dismiss button was clicked in -(void)selectedAssets:(NSArray*)_assets in the AssetTablePicker implementation.
Then I had to move -(void)selectedAssets:(NSArray*)_assets in ELCImagePickerController implementation to a background thread so the ui doesn’t lock up.
Thanks,
Albert C.
This is great. Thank you for the wonderful post!
Question: How would we make this so the user is limited to picking only one image?
Thanks again!
First I would like to thank for this great tutorial.
I come across one problem with this, when we have more number of images in image library, the application will crash. I think, because of putting images in array(memory issue). Is it possible to save images in database(sqlite, local memory)and then show in scroll view.
Please, help.
How to use it?
ELCImagePickerController *controller = [[ELCImagePickerController alloc] initImagePicker];
[controller setDelegate:self];
[self presentModalViewController:controller animated:YES];
//This is an error:
[controller selectedAssets:MY_IMAGE_ARRAY];??
//Thank you
[controller release];
It looks like you are trying to pass a array of images to the picker. That is not how it works. ELCImagePickerController allows you to pick images, then passes them back via the delegate to where ever you initiated it from.
Hi, firstly thank you very much for the code. The code runs perfectly well in Simulator 4.1 but when I try 4.0 or 4.2 it gets stuck on the Loading screen and it gives me the following comment on the GDB
2010-11-16 16:37:27.514 ELCImagePickerDemo[49819:6b03] A problem occured
Its from this line in the code.
ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
[library enumerateGroupsWithTypes:ALAssetsGroupAll
usingBlock:assetGroupEnumerator
failureBlock:^(NSError *error) {
NSLog(@"A problem occured");
}];
Somehow I am not able to figure out what is the problem, I have added the Asset Lib framework and everything. Please help.
CoderGirl, were you ever able to run this on a 4.2 device?
Hi, yes its working on 4.2, I had to makes some changes though to suit my needs, following is the change I made :-
-(void)preparePhotos {
dispatch_async(dispatch_get_main_queue(), ^{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSLog(@”hmmm 1″);
void (^assetGroupEnumerator)(ALAssetsGroup *, BOOL *) = ^(ALAssetsGroup *group, BOOL *stop) {
NSLog(@”hmmm 2″);
if(group != nil) {
[assetGroups addObject:group];
NSLog(@”Number of assets in group %d”, [group numberOfAssets]);
}
else {
NSLog(@”group is nil”);
}
[self performSelectorOnMainThread:@selector(reloadTableView) withObject:nil waitUntilDone:NO];
};
assetGroups = [[NSMutableArray alloc] init];
ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
[library enumerateGroupsWithTypes:ALAssetsGroupAll
usingBlock:assetGroupEnumerator
failureBlock:^(NSError *error) {
NSLog(@"A problem occurred %@",error);
}];
[library release];
[pool release];
NSLog(@”hmmm 3″);
});
}
Hope it works for you.
nice article!!!
Hi,
Great article. Just having some problems with the source code provided. Using simulator 4.2. and the latest xcode (downloaded last night), It builds fine, loads the album viewer, but when it loads up the images in the album, and then I select them, all the images just disappear. When I try clicking anywhere else it just crashes.
Console doesn’t spit out anything either which is annoying because I cant see whats going wrong.
Help?
I’ve found a problem with the code that prepares the group table. A couple of subtle problems are happening that I don’t yet understand. However, if you remove the NSLog statement from the closure then two problems appear.
ie : remove the line
NSLog(@”Number of assets in group=%d”, [group numberOfAssets]);
from the prepareImages method in the group level picker
void (^assetGroupEnumerator)(struct ALAssetsGroup *, BOOL *) = ^(ALAssetsGroup *group, BOOL *stop) {
if(group != nil) {
[assetGroups addObject:group];
//NSLog(@”Number of assets in group=%d”, [group numberOfAssets]);
}
[self performSelectorOnMainThread:@selector(reloadTableView) withObject:nil waitUntilDone:NO];
};
Now there are two things that occur
1. The count numbers for number of assets may not appear in the subsequent code that formats the table rows. Sometimes the count is incorrectly stated as zero.
2. If the user does not create an albums in the photo library but just syncs their images with the library as a whole, then when you pick the ‘PhotoLibrary’ group or the ‘Shared Photos’ group (these are the only ones which are visible in this case) then the user will see no photos found.
I’ve replaced the NSLog line with the following
int count = [group numberOfAssets]; //ignore the warning from not using ‘count’
And the code still works with this, so it looks as though there is something subtle going on here with how the closure is executing. I’ve no idea if this is a bug with the AssetsLibrary, but its certainly worth looking at as it could cause a serious problem with an app.
I’ve experienced this problem as well in my own code. Have you uncovered any reasons why this might be occurring? Thanks.
Trying to get this to work so far so good however my “DONE” button is not appearing when your in the picker it shows the cancel fading out but then fading back in it doesnt change to done so i cant really chose any images. Where do you change the nav bar from cancel to done?
When I run it, it seems that the orientation of the image gets lost. When I check the imageOrientation that gets saved in the dictionary, it also returns:
UIImageOrientationUp
Here’s how I’m checking the orientation.
UIImage *image = [dict objectForKey:UIImagePickerControllerOriginalImage];
UIImageOrientation orient = image.imageOrientation;
If you have any suggestions for figuring out the correct orientation of the image added to the dictionary, that would be great.
Thanks,
-Lary
OK, I figured it out how to add orientation to the code. Here’s the code:
ALAssetRepresentation *representation = [asset defaultRepresentation];CGImageRef imageRef = [representation fullScreenImage];
ALAssetOrientation orientation = [representation orientation];
UIImage *image = [UIImage imageWithCGImage:imageRef scale:1.0 orientation:(UIImageOrientation)orientation];
[workingDictionary setObject:image forKey:@"UIImagePickerControllerOriginalImage"];Hi,
Thanks for making this. This is saving me time instead of having to roll my own.
With that said, there are several places in this code with glaring memory leaks. I have already forked and committed a fix for one that I have submitted a pull request for. There are others that I’ve discovered that could’ve been avoided with an autorelease call but are much more deeply rooted, and I am, as of right now, unsure of what consequences might result in fixing them.
Regards.
Hi. thanks for sharing such a good code
when i use your code, I suddenly have a little thing to ask
have you tried to load photo library that over 500 photos inside?
when i load more than 500 photos it takes so long to load whole images
can i have your advice to get rid of this one?
I tried your sample code on several iPhones and it’s working only if there are not so many pictures stored on the device, once a folder has more then 200 images there is a delay and its shows loading for a few seconds.
However, I have one iPhone 4 with more then 800 images in several folders and it doesn’t even go past the “loading” stage.
I have one app called ” Stash Pro” (hedonic software) and they are able to open the photo library without any delay (even with 800 images) and you can import several pictures or even the complete folder.
Did they use a modified version of this script ? Or does anyone know how they made it ?
Thanks for your advise.
It is not working on my iPhone 3GS with iOS4.2.1. It worked on the simulator but it seems that it’s not able to find the photo directory in the device. The behaviour is similar to no photo in the simulator. It said “Loading…”
Thanks a lot for making this library available! Unfortunately I have the same issue as CodeBear. On both my 4.2.1 developer phones and also on my 4.3beta iPad the assetGroupEnumerator does not work. The last output in the console is:
sandboxd[944] : ELCImagePickerDe(942) deny file-write-data /private/var/mobile/Media/PhotoData
It looks like the system is keeping the app from accessing the album data (which indeed is outside the app sandbox). I read through Apple’s documentation on Assets and tried various stuff but I always end up with this error. Does anyone have an idea what the issue might be? Has anyone probably tested the code on a non-developer iPhone running 4.2.1 (with an ad hoc certificate for example or with an app from the app store)?
At the moment I’m really a bit lost with this problem. Of course I understand it’s not an issue with ELCImagePickerController, but rather with the iPhone 4.2.1 API and/or system.
Ok, looks like I found the problem. It seems that you can only make calls to the ALAssetsLibrary in the app’s main thread in 4.2 (or probably even earlier.
I changed the following line in the implementation of ELCImagePickerController.
[self performSelectorInBackground:@selector(preparePhotos) withObject:nil];becomes
[self preparePhotos];Hi ,
i buildup this code to iPad.i am using IOS SDK 4.2.When i’m pressing the “Launch ELC Image Picker Controller Button” it shows only empty table still the navigation bar holds the message “Loading..”.But in simulator it works fine.Please help to short it out.
i am new in iphone. i want to develop the webservice application. i am developing the application for the welcome view and it is reading the message from the webservice xml file .i am puting the code in the -viewdidload function but it is displaying the message.