Xcode Unrecognized Selector Error

Go To StackoverFlow.com

0

I've been having a ton of issues with this section of an app that I'm writing, I'm sure people here are getting sick of me so I'm going to try and solve all my questions in this post. I'm working on an app that behaves like a photo gallery, and I'm implementing the option to have the user delete photos from their gallery. To accomplish this, I decided to place an invisible button over each picture. When the user hits an "Edit" button, the hidden delete buttons over each picture become active. I'm using the same IBOutlet over each of the hidden buttons for simplicity, and I've tagged each button appropriately in Interface Builder. When the user taps the button over the picture, an alert view appears asking if they really want to delete it. If they click yes, I call removeObjectAtIndex and delete the image from the UI. But, when I click "Yes" in the alert view, I get an error from Xcode stating:

2012-04-04 11:26:40.484 AppName[608:f803] -[UIButton setImage:]: unrecognized selector sent to instance 0x6a922c0

2012-04-04 11:26:40.485 AppName[608:f803] Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[UIButton setImage:]: unrecognized selector sent to instance 0x6a922c0'*

I've been trying to figure out what is causing this for a few hours now to no avail. I'm not setting the image of a UIButton anywhere in my code. I did in IB, but I simply set the buttons types to Custom so that they appear invisible. I will post my entire file below, I can't find any issues in my code, so any help is much appreciated! Thanks. EDIT Here is the current version of the 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 = [NSMutableArray arrayWithObject:[NSData dataWithData:UIImagePNGRepresentation(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:[NSData dataWithData:UIImagePNGRepresentation(imageView2.image)]];

        [picker dismissModalViewControllerAnimated:YES];
        [self.popover dismissPopoverAnimated:YES];
        return;
    }

    if (imageView3.image == nil) {
        imageView3.image = img;

        [self.array addObject:[NSData dataWithData:UIImagePNGRepresentation(imageView3.image)]];

        [picker dismissModalViewControllerAnimated:YES];
        [self.popover dismissPopoverAnimated:YES];
        return;
    }

    if (imageView4.image == nil) {
        imageView4.image = img;

        [self.array addObject:[NSData dataWithData:UIImagePNGRepresentation(imageView4.image)]];

        [picker dismissModalViewControllerAnimated:YES];
        [self.popover dismissPopoverAnimated:YES];
        return;
}
}

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        self.title = NSLocalizedString(@"Photo Gallery", @"Photo Gallery");
        self.tabBarItem.image = [UIImage imageNamed:@"42-photos.png"];
    }
    return self;
}
////start of saving////


- (void)applicationDidEnterBackground:(UIApplication*)application {
    NSLog(@"Image on didenterbackground: %@", imageView);
    self.array = [NSMutableArray arrayWithObject:[NSData dataWithData:UIImagePNGRepresentation(imageView.image)]];

    [self.array addObject:[NSData dataWithData:UIImagePNGRepresentation(imageView2.image)]];
     [self.array addObject:[NSData dataWithData:UIImagePNGRepresentation(imageView3.image)]];
      [self.array addObject:[NSData dataWithData:UIImagePNGRepresentation(imageView4.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] initWithData:[self.array objectAtIndex:0]];
        imageView2.image = [[UIImage alloc] initWithData:[self.array objectAtIndex:1]];
        imageView3.image = [[UIImage alloc] initWithData:[self.array objectAtIndex:2]];
        imageView4.image = [[UIImage alloc] initWithData:[self.array objectAtIndex:3]];



        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];

    }




///// shows the hidden and invisible "delete" button over each photo.
- (IBAction)editButtonPressed:(id)sender {
    grabButton.hidden = YES;
    editButton.hidden = YES;
    backToGalleryButton.hidden = NO;
    tapToDeleteLabel.hidden = NO;
    deleteButton1.hidden = NO;
}
////

// 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;

}

- (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);
        [self.array removeObjectAtIndex: alertView.tag];
        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"];
}

Update: I added breakpoints, and discovered that ((UIImageView *)[self.view viewWithTag:alertView.tag]).image =nil; is the line that is causing the crash, I still can't figure out why though.

2012-04-04 17:37
by Henry F


1

This is an extension to @MichaelDautermann , who makes a very good point that a UIButton has a setImage:forState: method, but no setImage method. However, you ARE calling set image. Not on a button, but when you say imageView.image and imageView2.image. This invokes the setter method for the image view. I would set a breakpoint (or use NSLog and the %@ item) to ensure that imageView is in fact an imageView and not a button. If it somehow changed from under you, this could be causing the issue. Simply set a break point at those two lines and see if you even make it past them.

Additionally, if Xcode isn't popping you over to which line is actually causing the issue, check your crash logs. Symbolicated, the log will give you the line number. Or, a less direct approach would be to set breakpoints at the ends of the methods you provided in your answer, and see how many you get past. Once you crash, you can narrow down which method is causing you grief, and then start setting break points within the method until you get to the line in question.

UPDATE: You said in the comments that ((UIImageView *)[self.view viewWithTag:alertView.tag]).image =nil is what you have, but self.view is a UIControl. Changing the cast won't affect the result. Is the UIImageView whose image you are trying to delete a subview of a UIControl? If not, you're never going to get the image view back from viewWithTag. Generally, self.view refers to a view controller's view, so if you're getting a UIControl, my assumption is either your whole view is a UIControl, or you're doing this in the wrong class. Which class are you doing this in, and what is it a subclass of? It appears you are doing this in a view controller, but I just want to be sure. And again, in either case (UIControl or UIImageView), neither class responds to setImage.

2012-04-04 18:14
by jmstone617
Thanks a lot for your answer. I added in an NSLog(@"The image is a %@", imageView); in my imagePickerController method, and the output stated that it is indeed a UIImageView. However, I do have 2 invisible buttons over each of the image views. So, I added breakpoints throughout my project, and I narrowed the issue down to this line: ((UIImageView *)[self.view viewWithTag:alertView.tag]).image =nil; in my alertView method. This is the line I use to delete the image from the image view. Should I use a different way of doing that - Henry F 2012-04-04 18:26
So you're casting this as a UIImageView, but are you sure that self.view viewWithTag: is returning a UIImageView?? Specifically, if you have more than one view as a subview of self.view with the same tag, you're not guaranteed which one you'll get back. And if alertView's tag is 0, you may get back any other subview, since 0 is the default - jmstone617 2012-04-04 18:31
Ah that makes sense, thanks a lot. I added an NSLog(@"The view is%@", self.view); And the console stated that the view is a UIControl. Then, I added an NSLog(@"The view is%@", alertView.tag);, tried to delete the second picture, and the console stated that the view is UIAlertView, and the tag is 1 - Henry F 2012-04-04 18:48
I think you're missing my point. First of all, %@ and alertView.tag is a mismatch. You should use %i, since the tag is an int. Second of all, you still haven't shown that no other views have tag = 1. Third of all, and this is most important, if self.view is a UIControl, you're casting it as a UIImageView. It isn't. And what's more, neither responds to the message setImage - jmstone617 2012-04-04 18:54
Ah okay. Sorry I'm still extremely new to programming and they didn't cover any of this in the book I read. I changed the NSLog to show %i, and each tag is unique. So thats all good. And yes the self.view is a UIControl, should I change the line to ((UIControl *)[self.view viewWithTag:alertView.tag]).image =nil;? Thanks again for all of your help and I apologize for my dumb questions, I'm learning as I go here - Henry F 2012-04-04 18:59
Sweet thanks for the edited answer. Yes I'm doing this in the view controller, and the UIImageView whose image I'm trying to delete is subview of a UIControl. Thanks again for taking the time to help me out, I appreciate it - Henry F 2012-04-04 19:29
But is your view controller's entire view a UIControl - jmstone617 2012-04-04 19:34
let us continue this discussion in chatjmstone617 2012-04-04 19:34
Hey man, turns out I had my tags messed up. I tagged the invisible button over the UIImageView, thinking that it was the UIImageView when it wasn't. I tagged the image view and everything works. Thank you so much for taking the time to help me out, that is tremendously helpful - Henry F 2012-04-05 01:52
Good deal. Debugging is the best instructor - jmstone617 2012-04-05 02:49


2

I don't see setImage: being called in any of that code you pasted into your question, but I can tell you this: UIButton's setImage method actually requires a button state as a second parameter.

e.g.

[UIButton setImage: forState:]

I've linked Apple's documentation for you.

If your calls to setImage: don't have a second parameter, that would explain the "unrecognized selector error" you're seeing.

2012-04-04 17:42
by Michael Dautermann
Thanks for your answer. Yeah I've never called setImage: anywhere in my code, so thats what is throwing me off. I did set the buttons as Custom in IB just so that the button appears invisible, could that cause this - Henry F 2012-04-04 17:54
set a breakpoint on setImage: then and see if you can catch it being called and who is doing i - Michael Dautermann 2012-04-04 17:57
Thanks I'll give that a shot. But, where would a put the breakpoint since setImage is nowhere in my code? My imagePickerController method somewhat sets an image, but it never actually calls setImage - Henry F 2012-04-04 18:01
http://stackoverflow.com/questions/7156090/creating-breakpoint-in-xcode-for-unrecognized-selecto - Michael Dautermann 2012-04-04 18:06
Ah that is really neat, that will come in handy in the future. Thanks for showing me that. Should I just set the symbol to -[UIControl setImage:]: and build it? Sorry for the novice question, I've never used breakpoints before - Henry F 2012-04-04 18:10
don't worry... you'll get the hang of it soon. Look up the various documentation and tutorial things for symbolic breakpoints & XCode 4 and you should be able to catch the event happening and then figure out who or what is calling it - Michael Dautermann 2012-04-04 18:19
Ads