views:

675

answers:

2

I'm opening a new question to followup on my last one (http://stackoverflow.com/questions/2064513/superview-and-parentviewcontroller-nil-after-adding-a-subview). Basically I get that using subviews is a good idea, but that I shouldn't have a ViewController controlling a subview that lives inside another ViewController. Basically I'd like to do the following... I have two ViewControllers which share a common subview. I've created that subview as a nib called SearchDate.xib. The file owner is a corresponding class SearchDateView.m/h. That class has an outlet for the only element inside the UIView in the nib which is a label. The SearchDateView class also has a function for changing the value of the label in the SearchDateView.xib. I'd like both of my ViewControllers to load this nib but apparently I have no idea how to properly load the nib. No matter what I do at best nothing displays and at worst an exception is thrown. The apple docs talk about dragging in other instances of classes in IB right into your main view but that seems not to be working out. I have a SearchDateView outlet in my ViewController and I tried doing this on the controller's load view:

searchDateView = [[[NSBundle mainBundle] loadNibNamed:@"SearchDateView" owner:self options:nil] objectAtIndex:0];
[[self view] addSubview:searchDateView];

But I get this exception:

*** Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[<MainViewController 0x431fac0> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key searchDateLabel.'

I know I'm doing something totally wrong but what is the right way to have a nib, associated view class which updates some of the objects in that nib, and reuse that nib in different controllers?

EDIT: Given the comment perhaps this wasn't clear enough. I don't want to use the same nib file for an ENTIRE view - rather a subview. So for instance controller A has a map and also a SearchDateView, and controller B has a table view and a SearchDateView. So I'm wondering how to load a subview into multiple controllers...

+2  A: 

There should be no problem using the same NIB file for multiple controllers when each one is initialized using initWithNibName:bundle:. You don't normally load the controller's own nib file from within the controller though.

If you load a nib file using loadNibNamed::: then you get a NSArray with the objects defined therein, so you can't use it as a view directly. One way to get a view is to search through the array using for() or something to find the object you want, but if you set owner:self then it should connect to outlets connected to File's Owner in self as File's Owner will be self. But you can discard the return value in this case; you don't need the returned array. That may be your main problem (clobbering the outlet with the array) if you have that outlet connected.

It is possible to use loadNibNamed to load a specific view object (assuming you pick it out of the returned array), then display it somehow, but it's usually easier to use initWithNibName on the controller (in which case File's Owner will be the controller).

Oh, and you can also set the nib file for a controller in Interface Builder. There shouldn't be a problem with using the same nib for multiple controllers since essentially you'd just be telling Interface Builder to set up the nib file to do something like initWithNibNamed. Click the controller object and check the inspector window.

Update

I'd probably do this in order to use only one view in multiple controllers:

    NSArray *nib = [[NSBundle mainBundle] loadNibNamed:@"FooView" 
                                                 owner:self options:nil];
    for (id obj in nib)
        if ([obj isKindOfClass:[FooView class]])
            myNewView = (FooView *)obj;

(Stolen from Chapter 8: Cells 2 in the sample code from Beginning iPhone 3 Development.)

You could do this with outlets in IB, in which case you could leave out the for loop, but you'll probably need a superclass for both controllers declaring the outlet, and something to tell Interface Builder that File's Owner is an instance of that superclass so it knows about the outlet. Probably not worth the trouble.

Nimrod
Sorry maybe I wasn't too clear. I don't want to use the same nib file for an ENTIRE view - rather a subview. So for instance controller A has a map and also a SearchDateView, and controller B has a table view and a SearchDateView. So I'm wondering how to load a subview into multiple controllers.
deadroxy
I updated my answer to be more specific to your situation.
Nimrod
Yes the superclass seems to be the only "real" solution to my problem. I will probably refactor later but for now I've found some workarounds - thanks!
deadroxy
A: 

I have a SearchDateView outlet in my ViewController and I tried doing this on the controller's load view:

searchDateView = [[[NSBundle mainBundle] loadNibNamed:@"SearchDateView" owner:self options:nil] objectAtIndex:0];
[[self view] addSubview:searchDateView];

But I get this exception:

 *** Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[<MainViewController 0x431fac0> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key searchDateLabel.'

In the absence of Cocoa Bindings (which is only available in Cocoa, not Cocoa Touch), I don't think these two are related.

In Xcode, add a symbolic breakpoint on objc_exception_throw, then run your app in the debugger. When it breaks, look in the call stack. You'll be able to find where the problem really originated.

Peter Hosey