4

viewController's view is not loaded just after that viewController is pushed into navigation controller.

This is my code snippet.

- (void)myMethodInClassA {
    // window's root view controller is navigation controller
    UINavigationController *naviCtrl = (UINavigationController*)[UIApplication sharedApplication].keyWindow.rootViewController;
    MyViewController *myVC = [[MyViewController alloc] initWithNibName:@"MyViewController" bundle:nil];
    [naviCtrl pushViewController:myVC animated:NO];

    // at this point, myVC's view is NOT loaded
}

When I call myMethodInClassA, myVC's viewDidLoad is called AFTER that method returns. I'd expected that myVC's view is loaded just after navigation controller's pushViewController:animated: is called and before myMethodInClassA returns.

When exactly view controller's view is loaded? Apple's documentation just says it is loaded when it is first accessed. It's a bit ambiguous. why doesn't navigation controller's pushViewController: access view controller's view?

p.s. sorry for initial ambiguous question.

minorblend
  • 905
  • 1
  • 10
  • 23

6 Answers6

10

Pushing a view controller (VC) onto a navigation controller's stack makes the VC into a child view controller of the navigation controller (which is a container view controller). Creating such a child-parent relationship is a distinct step which does not cause the child VC's view to be loaded immediately. Rather the container VC loads the view at a later time. I believe there is no explicit specification for what "later" means - usually it will be when the container VC has decided that the time has come to integrate the child VC's view into the container VC's view hierarchy. But basically it simply happens at the discretion of the container VC's implementation.

That being said, anyone can force a VC's view to be loaded by simply accessing the VC's view property. For instance, in your code you could add this line

myVC.view;

which would trigger loadView and then viewDidLoad in MyViewController.

However, in your case if MyViewController needs to react to the event that it has been associated with a container VC, then it would be better to override one (or both?) of the following methods in MyViewController:

- (void) willMoveToParentViewController:(UIViewController*)parent
{
    // write your code here
}

- (void) didMoveToParentViewController:(UIViewController*)parent
{
    // write your code here
}

You need to be aware, though, that willMoveToParentViewController and didMoveToParentViewController are also invoked when MyViewController is popped from its parent navigation controller's stack. You can detect that this is the case by checking the parent argument for nil.

herzbube
  • 13,158
  • 9
  • 45
  • 87
  • 1
    I did workaround by calling `[myVC view]` already. But I didn't know why it's not loaded immediately. your answer is quite helpful to understand, and your suggestion of overriding `didMoveTo...` seems better than just call `[myVC view]`. thanks. – minorblend May 31 '13 at 12:00
  • @JoshChung Glad I could help. I have added another paragraph to my answer about `didMoveToParentViewController:` being called when the child VC is popped. – herzbube May 31 '13 at 12:11
2

(Swift 2) Since this question doesn't have an accepted answer...

What I ended up doing is create a convenience init at the child view controller:

convenience init() {
    self.init(nibName: "ChildViewController", bundle: nil)
    //initializing the view Controller form specified NIB file
}

and in the parentViewController's viewDidLoad():

let commentsView = CommentsViewController()
self.addChildViewController(commentsView)
self.momentsScrollView.addSubview(commentsView.view)
commentsView.didMoveToParentViewController(self)
Andre Simon
  • 665
  • 10
  • 16
1

As stated above,viewDidLoad gets called once when a view is pushed,you might want to do your stuff in viewWillAppear or viewDidAppear.

vin
  • 1,258
  • 5
  • 20
  • 33
0

Ya if that ViewController will be already pushed in navigationController stack then ViewDidLoad method will not be called again. First time when you will push that ViewController then viewDidLoad will be called. So if you need that your some functionality is to be executed every time then implement it in viewWillAppear method because it will be called every-time you push your viewController.

Hope it helps you.

Nishant Tyagi
  • 9,893
  • 3
  • 40
  • 61
0

are you pushing the view controller for the first tym?if YES then only viewDidLoad() of the controller will be called and if its already pushed and this is not the first tyn then viewWillAppear () will be called.(or) if you are making a new instance every tym u push it then viewDidLoad() will be called.

Kasaname
  • 1,491
  • 11
  • 15
0

I find that I have to call loadViewIfNeeded()

https://developer.apple.com/documentation/uikit/uiviewcontroller/1621446-loadviewifneeded

MH175
  • 2,234
  • 1
  • 19
  • 35