This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
iPhone, “More than maximum 5 filtered album lists trying to register. This will fail.” Error
When I'm adding images to UIImageViews via Popover Controller or Modal View Controller, after the 4th image, when I go to add the 5th, Xcode's debugger outputs: "Error: More than maximum 5 filtered album lists trying to register. This will fail." It will still let me add in 5+ pictures, but only 4 of them save. I've done some research on here about this, and found this question:
iOS 5 GM: <Error>: More than maximum 5 filtered album lists trying to register. This will fail
The answer in here appears as though it is a bug with Apple, and that it should be ignored. Well, Apple is usually (somewhat) quick about fixing their Xcode bugs, and this has been around for a while, so I'm starting to wonder what the real cause is. I think this error is related to my app only saving up to 4 of the pictures.
Here is the code I'm working with:
- (IBAction)grabImage {
self.imgPicker = [[UIImagePickerController alloc] init];
self.imgPicker.delegate = self;
self.imgPicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
_popover = [[UIPopoverController alloc] initWithContentViewController:imgPicker];
[_popover presentPopoverFromRect:self.imageView.bounds inView:self.imageView permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
}
else {
[self presentModalViewController:imgPicker animated:YES];
}
[self.imgPicker resignFirstResponder];
}
// Sets the image in the UIImageView
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingImage:(UIImage *)img editingInfo:(NSDictionary *)editInfo {
if (imageView.image == nil) {
imageView.image = img;
[self.array addObject:imageView];
[picker dismissModalViewControllerAnimated:YES];
[self.popover dismissPopoverAnimated:YES];
return;
}
if (imageView2.image == nil) {
imageView2.image = img;
NSLog(#"The image is a %#", imageView);
[self.array addObject:imageView2];
[picker dismissModalViewControllerAnimated:YES];
[self.popover dismissPopoverAnimated:YES];
return;
}
if (imageView3.image == nil) {
imageView3.image = img;
[self.array addObject:imageView3];
[picker dismissModalViewControllerAnimated:YES];
[self.popover dismissPopoverAnimated:YES];
return;
}
if (imageView4.image == nil) {
imageView4.image = img;
[self.array addObject:imageView4];
[picker dismissModalViewControllerAnimated:YES];
[self.popover dismissPopoverAnimated:YES];
return;
}
if (imageView5.image == nil) {
imageView5.image = img;
[self.array addObject:imageView5];
[picker dismissModalViewControllerAnimated:YES];
[self.popover dismissPopoverAnimated:YES];
return;
}
}
UPDATE: Here is my current code:
- (IBAction)grabImage {
if (self.imgPicker == nil) {
self.imgPicker = [[UIImagePickerController alloc] init];
}
self.imgPicker.delegate = self;
self.imgPicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
_popover = [[UIPopoverController alloc] initWithContentViewController:imgPicker];
[_popover presentPopoverFromRect:self.imageView.bounds inView:self.imageView permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
}
else {
[self presentModalViewController:imgPicker animated:YES];
}
[self.imgPicker resignFirstResponder];
}
From the other questions linked, it sounds like this is an Apple bug, but related to creating multiple UIImagePickerControllers. You're only presenting one image picker controller at a time, so maybe you should create one the first time you call your grabImage and then reuse it instead of creating a new one each time.
Related
Is there a way to decrease the memory when using the code below for the UIImagePickerController? The strange thing is that the memory is not coming above 26MB but it still shows the received memory warning. After taking a picture the app crashes. Memory warning only shows when choosing the camera, when choosing the library it's just fine.
- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex
{
if(buttonIndex==actionSheet.cancelButtonIndex){
return;
}
UIImagePickerControllerSourceType type = UIImagePickerControllerSourceTypePhotoLibrary;
if([UIImagePickerController isSourceTypeAvailable:type]){
if(buttonIndex==0 && [UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]){
type = UIImagePickerControllerSourceTypeCamera;
}
UIImagePickerController *picker = [[UIImagePickerController alloc] init];
picker.allowsEditing = NO;
picker.delegate = self;
picker.sourceType = type;
[self presentViewController:picker animated:YES completion:nil];
}
}
#pragma mark - Image Picker Controller delegate methods
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
UIImage *image = [info objectForKey:UIImagePickerControllerOriginalImage];
CLImageEditor *editor = [[CLImageEditor alloc] initWithImage:image];
editor.delegate = self;
[picker pushViewController:editor animated:YES];
}
I have an universal app that allows to select an image from the device photo library for later manipulation, the code works fine on the iPad but nothing happens on the iPhone, not even the cancel button and after an image is selected nothing happens neither here is my code:
-(IBAction)grabImage:(id)sender
{
if ( UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad )
{
imgPicker = [[UIImagePickerController alloc] init];
[imgPicker setDelegate:self];
popover = [[UIPopoverController alloc] initWithContentViewController:imgPicker];
[popover setDelegate:self];
CGPoint position = [view1.superview convertPoint:view1.frame.origin toView:nil];
CGRect popOverFrame = CGRectMake( position.x, position.y, self.view.frame.size.width, self.view.frame.size.height );
[popover presentPopoverFromRect:popOverFrame inView:self.view permittedArrowDirections:nil animated:NO];
[popover setPopoverContentSize:CGSizeMake(320, 480)];
[imgPicker release];
}
else
{
imgPicker = [[UIImagePickerController alloc] init];
imgPicker.delegate = self;
imgPicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
[self presentModalViewController:self.imgPicker animated:YES];
[imgPicker release];
}
}
-(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
pickedImage = [info objectForKey:UIImagePickerControllerOriginalImage];
CGImageRef imgRef = pickedImage.CGImage;
app->setImage( pickedImage, CGImageGetWidth(imgRef), CGImageGetHeight(imgRef) );
[[picker parentViewController] dismissModalViewControllerAnimated:YES];
// Enable texture siwth after an image has been loaded
[textureSwitch setEnabled:YES];
[textureSwitch setOn:YES];
app->isTextureDrawingOn = [textureSwitch isOn];
[fillsSwitch setOn:NO];
app->isFillsDrawingOn = [fillsSwitch isOn];
if ( UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad )
{
[popover dismissPopoverAnimated:YES];
}
ofLog(OF_LOG_VERBOSE, "cancel after selection");
}
-(void)imagePickerControllerDidCancel:(UIImagePickerController *)picker
{
[[picker parentViewController] dismissModalViewControllerAnimated:YES];
if ( UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad )
{
[popover dismissPopoverAnimated:YES];
}
ofLog(OF_LOG_VERBOSE, "did cancel");
}
Instead of using below code.
[[picker parentViewController] dismissModalViewControllerAnimated:YES];
Try this code
[self dismissModalViewControllerAnimated:YES];
and also check did you add UIImagePickerControllerDelegate in your interface file.
SOLUTION: (From my comment)
Try this [self.imgPicker dismissModalViewControllerAnimated:YES];
This will work.
For iOS 7: To dismiss a present view controller
[self.imgPicker dismissViewControllerAnimated: YES completion: NULL];
Add UIImagePickerControllerDelegate in your interface file
and then implement this code in your .m file
- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker {
[self dismissModalViewControllerAnimated:YES];
}
i hope it's solve your problem.
check viewWillAppear or viewDidAppear methods of your parent controller which calls the picker. On iPhone this methods will be called after picker view disappeared. They will not be called after popover disappeared on iPad. I just found error in my code where i set nil to ivar for picked image in viewWillAppear. it take me two days to understand what is happened ;)
Good luck!
An easiest solution:
Add UIImagePickerControllerDelegate in your interface file
and then implement this code in your .m file
- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker {
[picker dismissViewControllerAnimated:YES completion:nil];
}
Swift 3.0
Thanks to MBH this worked for me in my Xcode 8 and iOS 10 project:
internal func imagePickerControllerDidCancel(_ picker: UIImagePickerController){
dismiss(animated: true, completion: nil)
}
For closing it in Swift:
After adding those protocols to you ViewController: UINavigationControllerDelegate, UIImagePickerControllerDelegate
internal func imagePickerControllerDidCancel(picker: UIImagePickerController){
dismissViewControllerAnimated(true, completion: nil)
}
I have an app that behaves like a photo gallery. I'm implementing the ability for the user to delete the photos, by placing an invisible button over each UIImageView, and calling removeObject when they tap on the button. This code is working great, but its dependent upon tags. I need to tag every UIImageView / UIButton in interface builder in order for this to work. So, I'm now trying to save the images in a way that my tags will still work, which excludes using NSData.
So I'm totally lost on what to do right now. I'm very, very new to programming and am shocked that I even made it this far. Any help or advice on what or how to edit my code to make this work is much appreciated, thanks!
Here is my entire file just for reference:
- (IBAction)grabImage {
self.imgPicker = [[UIImagePickerController alloc] init];
self.imgPicker.delegate = self;
self.imgPicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
_popover = [[UIPopoverController alloc] initWithContentViewController:imgPicker];
[_popover presentPopoverFromRect:self.imageView.bounds inView:self.imageView permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
}
else {
[self presentModalViewController:imgPicker animated:YES];
}
[self.imgPicker resignFirstResponder];
}
// Sets the image in the UIImageView
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingImage:(UIImage *)img editingInfo:(NSDictionary *)editInfo {
if (imageView.image == nil) {
imageView.image = img;
[self.array addObject:imageView.image];
[picker dismissModalViewControllerAnimated:YES];
[self.popover dismissPopoverAnimated:YES];
return;
}
if (imageView2.image == nil) {
imageView2.image = img;
NSLog(#"The image is a %#", imageView);
[self.array addObject:imageView2.image];
[picker dismissModalViewControllerAnimated:YES];
[self.popover dismissPopoverAnimated:YES];
return;
}
if (imageView3.image == nil) {
imageView3.image = img;
[self.array addObject:imageView3.image];
[picker dismissModalViewControllerAnimated:YES];
[self.popover dismissPopoverAnimated:YES];
return;
}
if (imageView4.image == nil) {
imageView4.image = img;
[self.array addObject:imageView4.image];
[picker dismissModalViewControllerAnimated:YES];
[self.popover dismissPopoverAnimated:YES];
return;
}
if (imageView5.image == nil) {
imageView5.image = img;
[self.array addObject:imageView5.image];
[picker dismissModalViewControllerAnimated:YES];
[self.popover dismissPopoverAnimated:YES];
return;
}
- (void)applicationDidEnterBackground:(UIApplication*)application {
NSLog(#"Image on didenterbackground: %#", imageView);
[self.array addObject:imageView.image];
[self.array addObject:imageView2.image];
[self.array addObject:imageView3.image];
[self.array addObject:imageView4.image];
[self.array addObject:imageView5.image];
[self.user setObject:self.array forKey:#"images"];
[user synchronize];
}
- (void)viewDidLoad
{
self.user = [NSUserDefaults standardUserDefaults];
NSLog(#"It is %#", self.user);
self.array = [[self.user objectForKey:#"images"]mutableCopy];
imageView.image = [[self.array objectAtIndex:0] copy];
imageView2.image = [[self.array objectAtIndex:1] copy];
imageView3.image = [[self.array objectAtIndex:2] copy];
imageView4.image = [[self.array objectAtIndex:3] copy];
imageView5.image = [[self.array objectAtIndex:4] copy];
UIApplication *app = [UIApplication sharedApplication];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(applicationDidEnterBackground:)
name:UIApplicationDidEnterBackgroundNotification
object:app];
[super viewDidLoad];
}
// This is when the user taps on the image to delete it.
- (IBAction)deleteButtonPressed:(id)sender {
NSLog(#"Sender is %#", sender);
UIAlertView *deleteAlertView = [[UIAlertView alloc] initWithTitle:#"Delete"
message:#"Are you sure you want to delete this photo?"
delegate:self
cancelButtonTitle:#"No"
otherButtonTitles:#"Yes", nil];
[deleteAlertView show];
int imageIndex = ((UIButton *)sender).tag;
deleteAlertView.tag = imageIndex;
}
- (UIImageView *)viewForTag:(NSInteger)tag {
UIImageView *found = nil;
for (UIImageView *view in self.array) {
if (tag == view.tag) {
found = view;
break;
}
}
return found;
}
- (void)alertView: (UIAlertView *) alertView
clickedButtonAtIndex: (NSInteger) buttonIndex
{
if (buttonIndex != [alertView cancelButtonIndex]) {
NSLog(#"User Clicked Yes. Deleting index %d of %d", alertView.tag, [array count]);
NSLog(#"The tag is %i", alertView.tag);
UIImageView *view = [self viewForTag:alertView.tag];
if (view) {
[self.array removeObject:view];
}
NSLog(#"After deleting item, array count = %d", [array count]);
NSLog(#"Returned view is :%#, in view: %#", [self.view viewWithTag:alertView.tag], self.view);
((UIImageView *)[self.view viewWithTag:alertView.tag]).image =nil;
}
[self.user setObject:self.array forKey:#"images"];
}
#end
It seems you are using the tag just so you can identify which image view is being selected. You have an "invisible" button on top of each image? Is that right? I assume that is so you can handle a tap, which selects the image that is showing through the button?
There are lots of ways to do it, but a simple solution is to just recognize the tap, and "find" the image view underneath that tap. Drop a UITapGestureRecognizer onto your controller from within the storyboard. Ctrl-drag it into the code for your controller, and it will create an action method. Fill it in something like this...
- (IBAction)tapGesture:(UITapGestureRecognizer*)gesture
{
CGPoint tapLocation = [gesture locationInView: self.galleryView];
for (UIImageView *imageView in self.galleryView.subviews) {
if (CGRectContainsPoint(imageView.frame, tapLocation)) {
// This is the imageView that was tapped on!
// Do whatever you want with it now that you found it.
}
}
}
The previous comment is accurate; please think about how you're going to scale this up.
That said, you'll need to store and load images in some way, and that will always mean converting your UIImage objects to NSData. This applies whether you store them in NSUserDefaults, in files or in Core Data.
UIImage supports NSCoding, so you could use that. Read about how to use it, since you'll need it eventually. Or, if you know you'll always want to use PNG or JPEG formats, there are the functions UIImagePNGRepresentation(UIImage *image) and UIImageJPEGRepresentation(UIImage *image, CGFloat compressionQuality). To convert the NSData objects back to UIImage, use [UIImage imageWithData:NSData*] Here's what you could have in applicationDidEnterBackground:
NSMutableArray *dataArray = [NSMutableArray array];
[dataArray addObject:UIImagePNGRepresentation(imageView.image)];
[dataArray addObject:UIImagePNGRepresentation(imageView2.image)];
[dataArray addObject:UIImagePNGRepresentation(imageView3.image)];
[self.user setObject:dataArray forKey:#"images"];
[self.user synchronize];
Then, to retrieve these during viewDidLoad:
[self.array removeAllObjects];
NSArray *dataArray = [self.user objectForKey:#"images"];
for (NSData *imageData in dataArray)
[self.array addObject:[UIImage imageWithData:imageData]];
This will solve your immediate problem, but please don't consider it a permanent solution. Consider:
Store your images in files or Core Data, as NSUserDefaults is not
supposed to have large amounts of content.
Use a UITableView to display the images, so you can have an
arbitrary number instead of hard-coding for three.
If UITableView doesn't have the layout you need, create a custom
UIView subclass that displays an array of images and responds to taps appropriately.
Make sure your application can detect all the ways it may be
suspended or shut down. You may not always get the
ApplicationDidEnterBackground notification, or you may not have time
to save all your data after it happens. If you have multiple
UIViewControllers, this one may be unloaded without the application
itself receiving notifications.
I stored images in an NSMutableArray, and now I'm trying to get them to show up in viewDidLoad. I tried calling initWithContentsOfFile, but that doesn't seem to work. This is how the code looks:
imageView.image = [[UIImage alloc] initWithContentsOfFile:[self.array objectAtIndex:0]];
I'm not sure what I should use instead of initWithContentsOfFile to have the saved images load, I'm not even sure if I can save images in a plist through user defaults. I've been researching it for awhile now to no avail. Any help is much appreciated, thanks!
EDIT: Here is additional code:
- (IBAction)grabImage {
self.imgPicker = [[UIImagePickerController alloc] init];
self.imgPicker.delegate = self;
self.imgPicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
_popover = [[UIPopoverController alloc] initWithContentViewController:imgPicker];
[_popover presentPopoverFromRect:self.imageView.bounds inView:self.imageView permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
}
else {
[self presentModalViewController:imgPicker animated:YES];
}
[self.imgPicker resignFirstResponder];
}
// Sets the image in the UIImageView
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingImage:(UIImage *)img editingInfo:(NSDictionary *)editInfo {
if (imageView.image == nil) {
imageView.image = img;
[self.array addObject:imageView.image];
[picker dismissModalViewControllerAnimated:YES];
[self.popover dismissPopoverAnimated:YES];
return;
}
if (imageView2.image == nil) {
imageView2.image = img;
NSLog(#"The image is a %#", imageView);
[self.array addObject:imageView2.image];
[picker dismissModalViewControllerAnimated:YES];
[self.popover dismissPopoverAnimated:YES];
return;
}
if (imageView3.image == nil) {
imageView3.image = img;
[self.array addObject:imageView3.image];
[picker dismissModalViewControllerAnimated:YES];
[self.popover dismissPopoverAnimated:YES];
return;
}
}
- (void)applicationDidEnterBackground:(UIApplication*)application {
NSLog(#"Image on didenterbackground: %#", imageView);
[self.array addObject:imageView.image];
[self.array addObject:imageView2.image];
[self.array addObject:imageView3.image];
[self.user setObject:self.array forKey:#"images"];
[user synchronize];
}
- (void)viewDidLoad
{
self.user = [NSUserDefaults standardUserDefaults];
NSLog(#"It is %#", self.user);
self.array = [[self.user objectForKey:#"images"]mutableCopy];
imageView.image = [[UIImage alloc] initWithContentsOfFile:[self.array objectAtIndex:0]];
imageView2.image = [[UIImage alloc] initWithContentsOfFile:[self.array objectAtIndex:1]];
imageView3.image = [[UIImage alloc] initWithContentsOfFile:[self.array objectAtIndex:2]];
UIApplication *app = [UIApplication sharedApplication];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(applicationDidEnterBackground:)
name:UIApplicationDidEnterBackgroundNotification
object:app];
backToGalleryButton.hidden = YES;
tapToDeleteLabel.hidden = YES;
deleteButton1.hidden = YES;
[super viewDidLoad];
}
EDIT: This is how I'm tagging the images and deleting them based upon their tags:
- (IBAction)deleteButtonPressed:(id)sender {
NSLog(#"Sender is %#", sender);
UIAlertView *deleteAlertView = [[UIAlertView alloc] initWithTitle:#"Delete"
message:#"Are you sure you want to delete this photo?"
delegate:self
cancelButtonTitle:#"No"
otherButtonTitles:#"Yes", nil];
[deleteAlertView show];
int imageIndex = ((UIButton *)sender).tag;
deleteAlertView.tag = imageIndex;
}
- (UIImageView *)viewForTag:(NSInteger)tag {
UIImageView *found = nil;
for (UIImageView *view in self.array) {
if (tag == view.tag) {
found = view;
break;
}
}
return found;
}
- (void)alertView: (UIAlertView *) alertView
clickedButtonAtIndex: (NSInteger) buttonIndex
{
if (buttonIndex != [alertView cancelButtonIndex]) {
NSLog(#"User Clicked Yes. Deleting index %d of %d", alertView.tag, [array count]);
NSLog(#"The tag is %i", alertView.tag);
UIImageView *view = [self viewForTag:alertView.tag];
if (view) {
[self.array removeObject:view];
}
NSLog(#"After deleting item, array count = %d", [array count]);
NSLog(#"Returned view is :%#, in view: %#", [self.view viewWithTag:alertView.tag], self.view);
((UIImageView *)[self.view viewWithTag:alertView.tag]).image =nil;
}
[self.user setObject:self.array forKey:#"images"];
}
The problem is that you can't store images in a property list, which is what you're trying to do when you save it in the user defaults. You need to use an archiver to convert the image to an NSData object which you can store.
It looks like you're not passing a valid image path to the initializer method. Make sure the path is correct, and that it includes the image extension.
Really, though, you shouldn't be calling initWithContentsOfFile: in this case, because UIImageView's image property retains the image when you set it. That will usually lead to a memory leak (unless you're using automatic reference counting). Use one of the static initializers instead, such as imageNamed:, which has the added bonuses of using the system cache and also automatically loading the correct version of the image based on the characteristics of the device (for instance, it will load a higher resolution variant of the image if the device has a retina display).
I have an application that allows the user to select a photo from their camera roll, and display it in a UIImageView. But, after they tap on which image they would like to display, the camera roll's view does not disappear. So, I figured that I would need to simply call [sender resignFirstResponder];. But, this did not do the trick. I've been trying multiple things and doing searching around, but to no avail. I'm very new to Objective-C, so any help is much appreciated. Here is the code I'm working with:
(imgPicker is the UIImagePickerController.)
- (IBAction)grabImage(id)sender {
self.imgPicker = [[UIImagePickerController alloc] init];
self.imgPicker.delegate = self;
self.imgPicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
_popover = [[UIPopoverController alloc] initWithContentViewController:imgPicker];
[_popover presentPopoverFromRect:self.imageView.bounds inView:self.imageView permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
}
else {
[self presentModalViewController:imgPicker animated:YES];
}
[self.imgPicker resignFirstResponder];
}
And this may or may not be relevant to the issue:
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingImage:(UIImage *)img editingInfo:(NSDictionary *)editInfo {
if (imageView.image == nil) {
imageView.image = img;
[[picker parentViewController] dismissModalViewControllerAnimated:YES];
return;
}
if (imageView2.image == nil) {
imageView2.image = img;
[[picker parentViewController] dismissModalViewControllerAnimated:YES];
return;
}
}
You need just this line to dismiss modal picker in your delegate method:
[picker dismissModalViewControllerAnimated:YES];
resignFirstResponder in this case is useless
Try
[self dismissModalViewControllerAnimated:YES];
As you want to dismiss only picker view and not parent view of picker
you just have to use:
[picker dismissModalViewControllerAnimated:YES];
and you are done.