3

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?

TechZen
  • 64,370
  • 15
  • 118
  • 145
Althane
  • 103
  • 2
  • 3
  • 13

7 Answers7

12

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.

diachedelic
  • 2,195
  • 1
  • 24
  • 28
  • Came here to report exactly this. I was getting strange bad access crashes to various objects. Thats the first suggestion that I was having a memory issue. Originally I thought I had forgot to set the correct files owner. I was accidentally instantiating a view controller in the viewDidLoad method, which by the time the IBAction was called was nil! – anders Jul 08 '15 at 15:41
4

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.

Althane
  • 103
  • 2
  • 3
  • 13
  • Having the exact same problem, fixed after I routed through FirstResponder (but still don't know why this works) – jbnunn Feb 27 '10 at 16:32
0

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.

micahnyc
  • 49
  • 4
0

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.

TechZen
  • 64,370
  • 15
  • 118
  • 145
  • The class assigned to it is "MainScreenViewController", which is more or less an empty view controller class that's designed to react when one of the buttons is hit. I have SwitchViewController as a foreign object in the MainScreenView in IB, and have connected the IBOutlet viewButton to the UIBBI in MainScreenView (which is treated as a subview to SwitchViewController's view). If that helps any. – Althane Feb 21 '10 at 18:59
  • Was this the right answer? If so you need to check mark it. Otherwise the system will record this an unanswered question. – TechZen Feb 22 '10 at 12:40
0

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...
}
Ramaraj T
  • 5,184
  • 4
  • 35
  • 68
0

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.

atxe
  • 5,029
  • 2
  • 36
  • 50
0

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];
}
Anand
  • 10,310
  • 24
  • 90
  • 135