Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

UINavigationController NIB requires File's Owner to have a view?

I'm having a problem setting a View Controller nib's default View Outlet in Interface Builder. Here's my setup:

I have a TabBar based application where I load a Navigation Controller as a modal view...

MyNavCtrlrSubClass *menu = [[MyNavCtrlrSubClass alloc]initWithNibName:@"MenuController" bundle:nil];
[tabBarController presentModalViewController:menu animated:anim];

MenuController itself is structured as follows:

MenuController.xib
  File's Owner (MyNavCtrlrSubClass : UIViewController)
  Navigation Controller (UINavigationController)
    Navigation Bar (UINavigationBar)
    Root View Controller (Nib Name is set to load AnotherViewController.nib)
      Navigation Item -> (UINavigationItem)

This all works fine, except that when MyNavCtrlrSubClass is loaded, I get the following error:

Loaded the "MenuController" nib but the view outlet was not set

It's clear why this is happening - File's Owner doesn't have an outlet connection for its view. The question is what should I set as its view, and does something have to be set in the first place? The Navigation Bar is the only candidate in MenuController.xib, but doing this will just size the UINavigationBar itself to the fullscreen mode, so to speak.

I'm obviously missing something in IB, but what? MyNavCtrlrSubClass.m has no code itself, except an IBOutlet for the UINavigationController. Am I making a mistake trying to set this up entirely in IB? The idea is to keep the modal Navigation Controller in one nib, and all the views it loads in separate nibs, but since MenuController is just a container for the navigation and contains no views itself, I'm obviously designing it wrong. :)

If you're wondering why I'm not designing it some other way, it's because I'm trying to obey my (possibly mistaken) perception of how IB asks you to build an ideal hierarchy.

Any help would be greatly appreciated.

like image 656
Travis Dunn Avatar asked Jun 02 '09 17:06

Travis Dunn


2 Answers

I think you might not be understanding how the File's Owner is meant to be used in a NIB file. I've written up a response describing the file's owner under another question.

When you invoke this line:

[[MyNavCtrlrSubClass alloc] initWithNibName:@"MenuController" bundle:nil]

You create an instance of MyNavCtrlrSubClass, and tell it to load @"MenuController". Then in the MenuController.xib file, there is a second unrelated UINavigationController with things inside of it. When MenuController.nib is loaded at runtime, that second navigation controller will be created.

A second problem is that telling a UINavigationController to load a NIB file isn't really sensible because navigation controllers create and manage their own views. You really want to create the root view controller, and tell that view controller to load a NIB file.

Try this:

MyRootViewController *rootController = [[[MyRootViewController alloc] initWithNibName:@"AnotherViewController" bundle:nil] autorelease];
MyNavCtrlrSubClass *menu = [[MyNavCtrlrSubClass alloc] initWithRootViewController:rootController];

Where your XIB File looks like this:

  • File's Owner (Class set to MyRootViewController, view outlet connected to subsequent UIView)
  • UIView
    • Subview A
    • Subview B

After you're confortable with how all of this is working, you might also consider instantiating the navigation controller and root view controller in one XIB file like you were starting to do in the code you posted.

like image 80
Jon Hess Avatar answered Oct 14 '22 09:10

Jon Hess


The crux of this question is stated by Travis himself: "How would you load Navigation Controller nib, designing as much as possible in Interface Builder?" And also from the example, it looks like this means the UINavigationController and associated UIViewControllers.

With this interpretation, the answer is you cannot fully configure a UINavigationController and it's UIViewControllers in a single XIB. Yes it is intuitive to want to do this so you are not crazy.

When I say you cannot do this, I mean the most commonly used framework methods do not have a way to handle this. There is no [UINavigationController alloc] initWithMegaNibName. Yes you could stuff almost anything in a single XIB and write code to hydrate objects in special ways, but I don't think that's what you're looking for.

You could use two or more XIBs as Jon suggested, but then things are less self contained and so you have many folks who find it simpler to do part, or all, of the controllers in code.

Unfortunately there is not a 1:1 correspondance between Interface Builder capability and code like there is on other dev platforms. I generally prefer to be able let designers participate as much as possible in creating assets, but most of them I know do not code objective-c.

like image 32
whitneyland Avatar answered Oct 14 '22 08:10

whitneyland