2
votes

I'm working on a simple iPhone app.

I have 1 UINavigationController and 2 subclasses of UIViewController.

I have a MainWindow.xib file, a PersonListView.xib, and a PersonDetailView.xib.

The MainWindow.xib has the UINavigationController with the view linked over to the PersonListView.xib file.

The PersonListView.xib has the File's Owner listed as a PersonListViewController class.

I have some buttons on the PersonListView, along with labels and images. All displays correctly.

When I try to link a button on the PersonListView to my PersonListViewController class, the button is not firing....

The result: * Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '* -[UIViewController viewDetail]: unrecognized selector sent to instance 0x450d50'

If I go into the debug console and print-object 0x450d50, I get:

(gdb) print-object 0x450d50 (gdb)

The Interface Builder correctly shows the File's Owner as a PersonListViewController, so why would my button action (linked to the File's Owner) go to the superclass somehow?

EDIT1: Ok, what seems to be happening is that I wasn't getting an instance of the subclass unless, in my MainWindow.xib, I explicitly set the class of the view controller to my subclass.

There's still got to be something I'm missing, though, because surely I should be able to start up arbitrary subclasses of UIViewController just by swapping out the NIB file name from the main window?

EDIT2: (Response to Kevin) That's not what I'm saying regarding the contents of a XIB.

I have 3 XIBs:

MainWindow PeopleListView PeopleDetailView

The PeopleListView and PeopleDetailView each have an associated File's Owner that is a corresponding UIViewController subclass. Obviously, I need my events to go to the right controller classes as I move from page to page...but if I can only use a default UIViewController or one subclass, that will be much more difficult?

I can get the correct effect in code by manually setting up the UINavigationController with the correct root, but I feel like there should be a better way through InterfaceBuilder.

EDIT3: (to Kendall) I'm not using a tab bar. The model is the same, though, that the view in my navigation controller has to be wired to a single subclass, which seems a bit icky.

EDIT4: (to lostintransit) The PersonListViewController has the appropriate - (IBAction) viewDetail; method. The problem is that I can't find a way, in my MainWindow.xib, to flag the view inside my UINavigationController as "initially load this from PersonListView.xib, with a PersonListViewController as the view" that wouldn't make it difficult to replace the PersonListView with a PersonDetailView.

4

4 Answers

4
votes

I think you are using a tab bar, correct?

If so, think about it this way. Each tab defined in the MainWindow xib must be defined as the custom view controller type, because that is the type that the tab bar will create when it is loaded. The tab bar creates view controllers for each tab defined when it is loaded.

It's not enough to create an instance of just any view controller and then load your custom NIB (which is what the tab bar you have defined is doing right now), because the wiring in your custom view will have nothing to attach to.

Thus, make sure each view controller defined under each tab in MainWindow.xib (use the tree view in IB to examine this) is set to the right custom UIViewController type in addition to pointing at your custom XIB which must ALSO have the file's owner set to the correct type (though that's only important if you are wiring anything to Files Owner beyond the basic view).

0
votes

Changing the name of the xib has absolutely no effect on the contents of that xib. You have to change the class name in the Info panel if you want to change what subclass you're using.

0
votes

From the exception it appears that the binding was not done properly. The method signature does not seem to be right judging by the exception. Is the button action linked to a method with return type IBAction? The signature of the method should be

-(IBAction) methodName;

0
votes

I got the same mistake.

The problem is, that you didn't set the target of PersonListViewController.m.

Go to info of PersonListViewController.m, select targets section and make sure that the target of your app is checked.