views:

993

answers:

3

Have patience with me, I'm still learning Cocoa Touch. Other -viewDidLoad not being called question was unrelated to my issue, I did search.

I have FooViewController, a UIViewController subclass. FooViewController.xib has its File's Owner set to FooViewController. Additionally, I have Main, whose App Delegate is MyApplication and whose File's Owner is UIApplication. My primary nib is set to Main.

I am able to make the view appear on the screen, using this flow (code snipped for brevity):

UIWindow *main;

-(void)applicationDidFinishLaunching:(UIApplication*)application {
    [self showFooViewController];
    [main makeKeyAndVisible];
}

-(void)showFooViewController {
    fooViewController = [[FooViewController alloc] init];
    if(![[NSBundle mainBundle] loadNibNamed:@"FooViewController" owner:fooViewController options:nil]) {
        DebugF(@"Failed to load FooViewController");
        return;
    }

    // Add the view and put it in place
    UIView *view = [fooViewController view];
    CGRect cur = [view frame];
    cur.origin = CGPointMake(0.0f, 20.0f);
    [view setFrame:cur];

    [main addSubview:[fooViewController view]];
}

However, this message is not being sent to FooViewController:

- (void) viewDidLoad {
    DebugF(@"Hello!");
}

Total silence in gdb's output.

I've seen other Cocoa tutorials that show Instances and such in IB's document view, but I do not see these options in mine. Am I supposed to be instantiating fooViewController in the Nib? Did I miss a connection? In FooViewController.xib, File's Owner view is connected to the view in the Nib.

I'm sure this is a simple solution, and I have wandered down the wrong path. Halp!

+2  A: 

And I've answered my own question, so this may help future folks. Since I see viewDidLoad has, as its three top Googles in my suggest, "viewDidLoad not called", "viewDidLoad not getting called", and "viewDidLoad not firing", I imagine this is a usual mistake...

Changing:

fooViewController = [[FooViewController alloc] init];
if(![[NSBundle mainBundle] loadNibNamed:@"FooViewController" owner:fooViewController options:nil]) {
    DebugF(@"Failed to load FooViewController");
    return;
}

To:

fooViewController = [[FooViewController alloc] initWithNibName:@"FooViewController" bundle:[NSBundle mainBundle]];

Fixed the problem. Obviously a mistake in how I'm using Cocoa.

Jed Smith
It's a small thing, but if you pass nil for the bundle, it'll look in the main bundle.
Toon Van Acker
Unfortunately, the latter call makes it impossible to specify options, which means you can't use proxy objects. But it sounds like I'll just have to ignore viewDidLoad and call my own method manually.
Peter N Lewis
+3  A: 

I have not found documentation to back up the following, but this is what I've deduced by experiment / experience:

The viewDidLoad method is expected be called immediately after loadView is called, and it's up to whomever calls loadView to supply the extra call to viewDidLoad.

In some cases, the SDK will handle this behavior for you. Suppose you have a subclass of UIViewController called MyViewController; then:

  • If you access myViewController.view before you call loadView, then the superclass accessor is smart enough to call loadView for you, and viewDidLoad immediately thereafter.

As a result, if your code looks like this:

MyViewController *myViewController = [[MyViewController alloc] init];
[superView addSubview:myViewController.view];  // Calls viewDidLoad.

then both loadView and viewDidLoad will be called on your behalf.

However, if your code looks like this:

MyViewController *myViewController = [[MyViewController alloc] init];
[myViewController loadView];
[superView addSubview:myViewController.view];  // Doesn't call viewDidLoad.

then the view getter can see you've already loaded the view, and it assumes you also called viewDidLoad as well - so it doesn't call either. Ironically, the extra function call here prevents viewDidLoad from getting called.

Tyler
Hm, interesting. Thanks!
Jed Smith
According to the documentation "You should never call this method [loadView] directly".
Peter N Lewis
Thanks, Peter - I see what you're referring to. Here's the link, in case anyone wants to read the original source (from Apple):http://developer.apple.com/iphone/library/documentation/uikit/reference/UIViewController_Class/Reference/Reference.html#//apple_ref/occ/instm/UIViewController/loadView
Tyler
A: 

I had the same problem because I forgot to connect the view of UITableViewController to the actual UITableView in interface builder.

Casebash