Question

I'm working on my first real iPhone app, a simple To-Do list application to help me organize stuff, except I'm getting an "unrecognized selector sent to instance 0x".

Specifically:

2010-02-20 14:30:09.200 ToDoApp[88562:20b] *** -[NSCFDictionary switchViews:]: unrecognized selector sent to instance 0x3d22de0

2010-02-20 14:30:09.201 ToDoApp[88562:20b] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[NSCFDictionary switchViews:]: unrecognized selector sent to instance 0x3d22de0'

I've looked around and figured out that it might be a connection problem in IB, but I'm new to this whole connecting thing (man, I wish they supported Java or Python), so here's how it's laid out. I've got 3 classes, a SwitchViewController, a MainScreenViewController, and a ToDoListViewController. When I hit a button on MainScreenViewController, I trigger the "switchViews" function that's throwing this problem. They way I've got it set up is that the button (a UIBarButtonItem) has the "sentAction" go to switchViews. This ViewButton has its reference outlet as a IBOutlet in SwitchViewController.

So here's the .h for SVC:

#import <UIKit/UIKit.h>

@class MainScreenViewController;
@class ToDoListViewController;
@class EditViewController;

#define kMinimumGestureLength 25
#define kMaximumVariance 5

@interface SwitchViewController : UIViewController {
 MainScreenViewController *mainScreenViewController;
 ToDoListViewController *toDoListViewController;
 EditViewController *editViewController;
 IBOutlet UIBarButtonItem *viewButton;
 CGPoint gestureStartPoint;
}

@property (retain, nonatomic) MainScreenViewController *mainScreenViewController;
@property (retain, nonatomic) ToDoListViewController *toDoListViewController;
@property (retain, nonatomic) EditViewController *editViewController;
@property (retain, nonatomic) IBOutlet UIBarButtonItem *viewButton;
@property CGPoint gestureStartPoint;
-(IBAction)switchViews:(id)sender;  

And for the switchViews function:

-(IBAction) switchViews:(id)sender
{
 NSLog(@"Switching views");
 if(self.toDoListViewController.view.superview == nil){
  if(self.toDoListViewController ==nil){
   ToDoListViewController *toDoVC = [[ToDoListViewController alloc]     initWithNibName:@"ToDoListView" bundle:nil];
   self.toDoListViewController = toDoVC;
   //[toDoVC release];
  }
  [mainScreenViewController.view removeFromSuperview];
  [self.view insertSubview:toDoListViewController.view atIndex:0];
 }
 else{
  if(self.mainScreenViewController == nil){
   MainScreenViewController *mainController =     [[MainScreenViewController alloc] initWithNibName:@"MainScreenView" bundle:nil];
   self.mainScreenViewController = mainController;
   //[mainController release];
  }
  [toDoListViewController.view removeFromSuperview];
  [self.view insertSubview:mainScreenViewController.view atIndex:0];
 }
}

So in short, I'm totally lost, and this is really frustrating. Anyone have any advice, or need any more code?

Was it helpful?

Solution 2

Okay, got the solution pointed out to me. Should have had it routed through FirstResponder (I ... really don't understand why that works, but at this point I'm just happy it works.)

I'm not sure how first responder works anyways (none of the books I have really mention it), but it... works? If someone wants to give me a rundown, that'd be useful... but this question has been answered.

OTHER TIPS

We just ran into the same problem. It seems we released the ViewController object in the AppDelegate and then our nib view tried to invoke an IBAction (on the view controller). Half the time we were getting "EXC_BAD_ACCESS" (aka messaging a released object), and half the time we were getting "unrecognized selector sent to instance" of NSCFString, NSCFArray, all sorts of things (aka messaging an area of memory now taken up by a different object).

Just check your ViewController hasn't been released.

I'm going to guess the problem is in your nib file.

The error means that upon clicking the button, the button tries to send a message/method-call of switchView to an NSDictionary object which of course has no such method. The error then lays in where the buttons action is pointed.

Check the nib for this view. Look at the File Owner and check the class assigned to it. Make sure it is SwitchViewController and not a dictionary for some reason. If the File Owner property is set to a dictionary class it will load a dictionary and try to send the action method it to it.

The right answer is this:

The view controller that we assign as the first screen in the app delegate shouldn't be released in the - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions method. In your case the first screen is MainScreenViewController.

It (MainScreenViewController instance)should be released in app delegate's dealloc method.

- (void)dealloc
{
    [_window release];
    [mainScreenViewController release];
    [super dealloc];
}

This might also help. The Analyzer routine recommended I release a few objects, and I did. Turns out, I needed those objects in the app. In the xAppDelegate.m file (or whatever) in the appDidFinishLaunching method/message/function/routine/thing, use

UINavigationController *navController = [[UINavigationController alloc] init];

instead of

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

Also, Analyzer recommended I release the object I pushed onto the nav controller. Big mistake. That file was my menu screen and when I pressed a button, I received a unrecognized selector sent to instance. Apparently, it was calling IBAction on NSString and NSDictionary, which is not good.

FYI I was getting this when using ARC and the xib was being loading and put onto the screen, but somehow the VC itself was not being retained.

I solved it by adding a variable to store reference in the VC that was presenting it.

The problem is, you have initiated the UIViewController instance as a method variable. So the view controller have no scope after the execution of the method and so it is released from the memory cycle. So you have to make your view controller instance as class level.

  @interface SwitchViewController () {
         ToDoListViewController *toDoVC;
         MainScreenViewController *mainController;
    }



-(IBAction) switchViews:(id)sender
{
     if (!toDoVC)
          toDoVC = [[ToDoListViewController alloc]     initWithNibName:@"ToDoListView" bundle:nil];
     if (!mainController)
          mainController =     [[MainScreenViewController alloc] initWithNibName:@"MainScreenView" bundle:nil];

 //Your stuff with the view controllers...
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top