137

When working with views and view controllers in an iPhone app, can anyone explain the difference between loadView and viewDidLoad?

My personal context, is that I build all my views from code, I do not and will not use Interface Builder, should that make any difference.

I've found that often when I add init code to loadView, I end up with an infinite stack trace, so I typically do all my child-view building in viewDidLoad...but it's really unclear to me when each gets executed, and what is the more appropriate place to put init code. What would be perfect, is a simple diagram of the initialization calls.

Thanks!

TheNeil
  • 3,321
  • 2
  • 27
  • 52
ryan.scott
  • 2,215
  • 2
  • 18
  • 16

8 Answers8

200

I can guess what might be the problem here, because I've done it:

I've found that often when I add init code to loadView, I end up with an infinite stack trace

Don't read self.view in -loadView. Only set it, don't get it.

The self.view property accessor calls -loadView if the view isn't currently loaded. There's your infinite recursion.

The usual way to build the view programmatically in -loadView, as demonstrated in Apple's pre-Interface-Builder examples, is more like this:

UIView *view = [[UIView alloc] init...];
...
[view addSubview:whatever];
[view addSubview:whatever2];
...
self.view = view;
[view release];

And I don't blame you for not using IB. I've stuck with this method for all of Instapaper and find myself much more comfortable with it than dealing with IB's complexities, interface quirks, and unexpected behind-the-scenes behavior.

Marco
  • 14,977
  • 7
  • 36
  • 33
  • ahhhh, thank you for an explanation, finally! I've shied away from the idiom of allocating a temporary variable, then setting to self.view, then releasing...it seemed somehow awkward, unnecessary. I can now understand why that decision would have led me down the path where I now find myself. – ryan.scott Feb 23 '09 at 04:29
  • I have such code and there is no recursion. why? `-(void) loadView { // Frame for Hypnosis view CGRect frame = [[UIScreen mainScreen] bounds]; // Create a Hipnosis view v = [[HypnosisView alloc] initWithFrame:frame]; self.view = v;` – user2054339 Aug 06 '13 at 07:54
46

loadView is the method in UIViewController that will actually load up the view and assign it to the view property. This is also the location that a subclass of UIViewController would override if you wanted to programatically set up the view property.

viewDidLoad is the method that is called once the view has been loaded. This is called after loadView is called. It is a place where you can override and insert code that does further initial setup of the view once it has been loaded.

KlimczakM
  • 12,576
  • 11
  • 64
  • 83
Ecton
  • 10,702
  • 2
  • 35
  • 44
14
viewDidLoad()

is to be used when you load your view from a NIB and want to perform any customization after launch

LoadView()

is to be used when you want to create your view programmatically (without the use of Interface Builder)

Preetam Jadakar
  • 4,479
  • 2
  • 28
  • 58
ashokdy
  • 1,001
  • 12
  • 21
  • This may have some problem, I have test when my view controller was not associate with NIB file, viewDidLoad still called – ruandao Mar 04 '16 at 13:05
11

Just adding some code examples to demonstrate what NilObject said:

- (void)loadView
{
    // create and configure the table view
    myTableView = [[UITableView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame] style:UITableViewStyleGrouped];   
    myTableView.delegate = self;
    myTableView.dataSource = self;
    myTableView.scrollEnabled = NO;
    self.view = myTableView;

    self.view.autoresizesSubviews = YES;
}

- (void)viewDidLoad 
{
  self.title = @"Create group";

  // Right menu bar button is to Save
  UIBarButtonItem *saveButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"Save" style:UIBarButtonItemStyleDone target:self action:@selector(save)];
  self.navigationItem.rightBarButtonItem = saveButtonItem;
  [saveButtonItem release];
}
alamodey
  • 14,320
  • 24
  • 86
  • 112
  • 4
    so, between the two of you, is it accurate to say that loadView is where I should do the alloc/init of my controller's self.view, and child views should be handled in viewDidLoad (or later)? – ryan.scott Feb 22 '09 at 02:04
2

To prevent an infinite loop from happening when you read self.view, call the class' super implementation when you load a view. The super implementation will allocate a new UIView for you.

- (void) loadView {
[super loadview];

// init code here...

[self.view addSubView:mySubview1]; //etc..

}
futureelite7
  • 11,462
  • 10
  • 53
  • 87
  • 6
    I could swear Apple's documentation said you should not call `[super loadView];`. That was contradicted in the examples, but I think the docs said it correctly (I have found numerous bugs in examples over time). `[super loadView]` is needed for UITableViewController etc, though. However! Any post-load setup (e.g. adding extra subviews) should be done in viewDidLoad. – Ivan Vučica Mar 10 '11 at 19:44
  • I have called [super loadView] without any side effects so far. It may be true if you intend to set self.view to something you made yourself though. – futureelite7 Mar 11 '11 at 00:58
  • If you call [super loadView] inside loadView then it will attempt to load the view from a nib if available with default name. So you need to be careful. – Ian1971 Apr 28 '11 at 10:23
  • And if you call [super loadView], you initialize self.view in super loadView method – Alex Nazarov Jan 09 '14 at 09:39
1

The easiest way to use loadView is to make some type of base view controller, like MyBaseViewController which is subclass of UIViewController. In it's loadView method create view in this way:

-(void) loadView {
    if ([self viewFromNib]) {
        self.view = [self viewFromNib];
    } else {
        self.view = [[[UIView alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
    }
    self.view.autoresizingMask = UIViewAutoresizingFlexibleHeight;
    self.view.backgroundColor = [UIColor whiteColor];
}

And when you need to make some view controller you just use subclass of MyBaseViewController and in it's loadView controller you just call [super loadView] like this

//sucblass loadView
-(void) loadView {
    [super loadView];

    //rest of code like this..
    UILabel *myLabel = [[UILabel alloc] initWithFrame:myFrame];
    [self.view addSubview:myLabel];
    [myLabel release];
}
Josip B.
  • 2,434
  • 1
  • 25
  • 30
1

loadView() is called when your controller is asked to create its self.view. You can do it by yourself like

self.view = [UIView alloc] init...];

Or your controller's parent UIController class has already a method name -loadView() which initializes your self.view into blank view. Then you can call

[super loadView];

I really recommend the second approach as it encourages the inheritance. Only if your view controller is not directly inherited from UIViewController.

Dulguun Otgon
  • 1,925
  • 1
  • 19
  • 38
0

The definition given by Apple on viewDidLoad mentioned that it is called after the controller’s view is loaded into memory. To put it in a simple term, it is the first method that will load.

You might be thinking under what condition will this method being fully utilized? The answer is, basically whatever you wanted the app to load first. For instance, you might want a different background color, instead of white, you could perhaps choose blue.

Gulsan Borbhuiya
  • 188
  • 2
  • 11