How does View Controller Containment work in iOS 5?

53,559

Solution 1

The UIViewController docs are pretty clear on when and when not to call willMove/didMove methods. Check out the "Implementing a Container View Controller" documentation.

The docs say, that if you do not override addChildViewController, you do not have to call willMoveToParentViewController: method. However you do need to call the didMoveToParentViewController: method after the transition is complete. "Likewise, it is is the responsibility of the container view controller to call the willMoveToParentViewController: method before calling the removeFromParentViewController method. The removeFromParentViewController method calls the didMoveToParentViewController: method of the child view controller."

Also, there is an example worked out here and sample code here.

Good Luck

Solution 2

This part is not correct:

[vc willMoveToParentViewController:self];
[self addChildViewController:vc];
[self.view addSubview:vc.view]; // or something like this.
[vc didMoveToParentViewController:self];

According to the docs:

When your custom container calls the addChildViewController: method, it automatically calls the willMoveToParentViewController: method of the view controller to be added as a child before adding it.

So you don't need the [vc willMoveToParentViewController:self] call. It is done automatically when you call [self addChildViewController:vc]. Here's the code sample again:

[self addChildViewController:vc];
// [vc willMoveToParentViewController:self] called automatically
[self.view addSubview:vc.view]; // or something like this.
[vc didMoveToParentViewController:self];

For removing view controllers:

The removeFromParentViewController method automatically calls the didMoveToParentViewController: method of the child view controller after it removes the child.

Presumably this call is [oldVC didMoveToParentViewController:nil].

[vc willMoveToParentViewController:nil];
[vc.view removeFromSuperview];
[vc removeFromParentViewController];
// [vc didMoveToParentViewController:nil] called automatically
Share:
53,559

Related videos on Youtube

Gregory Higley
Author by

Gregory Higley

Author of CoreDataQueryInterface. If you work with Core Data and would rather say this… managedObjectContext.from(Employee) .filter{ $0.department.name == "Engineering" } .order{ $0.lastName } than set a bunch of properties on NSFetchRequest, you probably want to use CDQI.

Updated on October 31, 2020

Comments

  • Gregory Higley
    Gregory Higley over 3 years

    In WWDC 2011 Session 102, Apple introduced View Controller Containment, which is the ability to create custom view controller containers, analogous to UITabBarController, UINavigationController, and the like.

    I watched the examples several times. There are a flurry of methods associated with this pattern, but it was a little hard to figure them out exactly. I'm going to post here what I think is going on and see if the community will confirm or disconfirm my suspicions.

    Scenario 1: Moving from no parent to a new parent view controller

    [vc willMoveToParentViewController:self];
    [self addChildViewController:vc];
    [self.view addSubview:vc.view]; // or something like this.
    [vc didMoveToParentViewController:self];
    

    Do the first two lines have to occur in the order given, or can they be reversed?

    Scenario 2: Moving from a parent view controller to no parent view controller

    [vc willMoveToParentViewController:nil];
    [vc.view removeFromSuperview];
    [vc removeFromParentViewController];
    

    Is it also necessary to call [vc didMoveToParentViewController:nil]? The examples in Session 102 did not do this in this scenario, but I don't know whether that was an omission or not.

    Scenario 3: Moving from one parent view controller to another

    This will likely occur in the following way, because the logic in each parent view controller will be encapsulated.

    // In the old parent
    [vc willMoveToParentViewController:nil];
    [vc.view removeFromSuperview];
    [vc removeFromParentViewController];
    
    // In the new parent
    [vc willMoveToParentViewController:self];
    [self addChildViewController:vc];
    [self.view addSubview:vc.view];
    [vc didMoveToParentViewController:self];
    

    Questions

    My main question is this: Is this how view controller containment should work, in general? Are the mechanics given above correct?

    Is it necessary to call willMoveToParentViewController before calling addChildViewController? This seems like the logical order to me, but is it strictly necessary?

    Is it necessary to call didMoveToParentViewController:nil after calling removeFromParentViewController?

  • Gregory Higley
    Gregory Higley over 12 years
    I see, so addChildViewController should be balanced with didMoveToParentViewController and willMoveToParentViewController should be balanced with removeFromParentViewController. This is exactly what I was looking for. Not sure how I missed it in the docs.
  • user4951
    user4951 over 11 years
    Why not? Why you do not have to call willMoveToParentViewController but hae to call didMoveToParentViewController?
  • Admin
    Admin over 11 years
    Because that's what the docs say. Apple obviously feel we don't need to know.
  • Chris
    Chris over 11 years
    The reason is for animation's sake: Say you're creating your own navigation controller. At the start of a slide-in animation, 'willMove' needs to be called, and at the end of the animation, 'didMove' needs to be called. Now when you call 'addChild' at the start of the animation, it automatically calls 'willMove' for you. But it can't know when the animation (if there is one) finishes, so you have to call 'didMove' manually at the end of animation (or immediately on no animation).
  • Chris
    Chris over 11 years
    And as for a 'slide out' animation, eg the child is being removed, you have to call 'willMove' manually at the start of the animation, because uikit otherwise wouldn't know when to call your child VC's 'viewWillDisappear'. And at the end of the animation, when you call removeFromParentViewController, it can call 'didMove' automatically for you.
  • Adrian
    Adrian about 9 years
    it appears that if done otherwise, even if it seems to work, presentingViewController is not set on the presentedViewController.
  • Robert
    Robert almost 8 years
    Docs say call didMoveToParentViewController "immediately after calling the addChildViewController: method", it does not specify when you actually add the child subview. I wonder if everyone has got this wrong. Is there an example in some Apple Docs we can check this against?
  • bunkerdive
    bunkerdive about 7 years
    Note: you do need to call willMoveToParentViewController prior to addChildViewController if the item you are moving is a custom class with overridden addChildViewController (unless your override calls it internally)