0

I have an application in which I need to be able to update what buttons may appear on the home screen and have elected to use core data to allow me to update the controlling property via XML. The core data seems to be working well and updating, and the buttons are being created, however, for some reason, the selector doesn't seem to be retained as it crashes every time I click on the button. The error log doesn't say anything - except one time when it did say "unrecognized selector sent to instance". Here is the method I use to create the buttons:

- (void)setUpNavigationButtons {

    int i = 0;

    for (Features *myFeature in self.features) {

        CGRect buttonRect = [self makeFeatureButtonFrame:[self.features count] withMember:i];

        UIButton *aButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
        [aButton setFrame:buttonRect];

        [aButton addTarget:self action:@selector(buttonTouched:) forControlEvents:UIControlEventTouchUpInside];
        [aButton setTitle:[NSString stringWithFormat:@"%@",myFeature.name] forState:UIControlStateNormal];

        [self.view addSubview:aButton];

        i++;

    }
}

Here is the the selector method, in the same view controller class:

- (void)buttonTouched:(id)sender{

    NSLog(@"feature selected");

}

Any help is much appreciated. Please let me know if more of the code is required to ascertain anything meaningful. I don't want to ask folks to read through a mountain of it if only a molehill is required.

UPDATE: 4/27/2011 In response to the comments in the checked answer below, I am posting the code that launches the view controller. I've not had a problem with this in the past, but it's entirely possible I've picked up some bad technique in here. This is from the method application:didFinishLaunchingWithOptions method in the AppDelegate. Anyway, here is the code:

UINavigationController *navigationController = [[[UINavigationController alloc]  init] autorelease];


HomeViewController *root = [[HomeViewController alloc] initWithNibName:@"HomeViewController" bundle:nil];
root.title = companyName;
root.context = [self managedObjectContext];
[navigationController pushViewController:root animated:NO];

[window addSubview:navigationController.view];

[root release];

[self.window makeKeyAndVisible];
return YES;
Carl
  • 1,246
  • 3
  • 21
  • 39
  • Is it saying that `buttonSelected:` is an unrecognized selector for your View Controller (`self`)? – Chris Wagner Apr 26 '11 at 20:02
  • It isn't that specific, it only says "unrecognized selector sent to instance" - but the view controller being the instance, that's what I think it's saying. – Carl Apr 26 '11 at 20:21
  • In response to your code: your nav controller is autoreleased and not retained by anything, so if that's the object which has your action method in it, there's your problem. – jscs Apr 27 '11 at 19:14
  • ...and if that's _not_ the object with the action method in it, that is _another_ problem. – jscs Apr 27 '11 at 19:35
  • Ok, that was it. I made the navigationController a property of the AppDelegate, removed the autorelease and released it in the dealloc method. Then I was able to remove the [self retain] call and it worked beautifully. It also solved another problem I was having pushing a table view controller once the button was pressed. It all makes sense now since nothing owned that navigation controller. Thanks much indeed. – Carl Apr 27 '11 at 19:45

1 Answers1

0

Disclaimer; I'm guessing here.

Perhaps your controller isn't sticking around in memory, and it needs to be retained?

[aButton addTarget:[self retain] action:@selector(buttonTouched:) forControlEvents:UIControlEventTouchUpInside];

NOTE: THE ABOVE CODE IS BAD. It merely identified the problem in the original question. See comments below for details.

That code above is probably bad if it fixes the issue, unless each button also sends [target release] when being destroyed.

Also, you should use IBAction instead of void for button actions:

- (IBAction)buttonTouched:(id)sender{
    NSLog(@"feature selected");
}
Dave
  • 12,408
  • 12
  • 64
  • 67
  • I thought IBAction was specific to buttons created in the NIB files, no? – Carl Apr 26 '11 at 20:29
  • Thanks much - this did the trick. I will have to figure out how to release the buttons, but I don't think that should be too difficult. – Carl Apr 26 '11 at 20:32
  • 1
    Yes Carlton, `IBAction` and `void` are equivalent with the exception that an `IBAction` will appear in Interface Builder so that you can assign an event to it. – Chris Wagner Apr 26 '11 at 20:40
  • 2
    The fact that `[self retain]` stopped the crashes is only indicative of a problem elsewhere in your code. You should never need to retain `self`. – kubi Apr 26 '11 at 20:49
  • 1
    Kubi is correct: this is _not right_. You don't retain `self`. If this object is being deallocated when it shouldn't be, then _another object_ (probably the view controller that owns the xib) needs to retain it. – jscs Apr 26 '11 at 20:56
  • I also agree with kubi and Josh Caswell. My answer was meant to find the root problem, not necessarily solve it (I'll update the answer to reflect that). I'm not sure how your controller is initialized, and what maintains it. If it needs to stick around in memory indefinitely, one idea would be to make it a Singleton class (http://stackoverflow.com/questions/145154/what-does-your-objective-c-singleton-look-like/4312421#4312421). – Dave Apr 26 '11 at 22:04
  • 1
    Because your suggestion helped the openingsposter identify the issue and because you warned about the bad use of retain in your suggestion, I've given your suggestion +1. – Wolfgang Schreurs Apr 26 '11 at 22:09
  • Thanks for the further input. I will investigate further to see where the root problem lies. – Carl Apr 27 '11 at 18:06
  • Thanks again - I have posted an update above showing how the view controller is created. – Carl Apr 27 '11 at 18:29
  • @Wolfgang: the fact that this object was even around long enough to call retain on itself is in principle predictable, but in practice just dumb luck. This is next to useless as a general debugging technique. – jscs Apr 27 '11 at 19:21