iOS 5
View Controller Containment
iOS Development
iOS Programming
Objective-C

How does View Controller Containment work in iOS 5?

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

Introduction

iOS 5 introduced official view controller containment so one view controller could own and manage other view controllers cleanly. Instead of building giant monolithic controllers or manually forwarding everything yourself, you can compose a screen from parent and child controllers with a defined API and lifecycle.

What Containment Actually Means

A parent view controller manages child view controllers. The parent decides where a child lives in the interface, while each child still owns its own view lifecycle, outlets, and presentation logic.

Apple's built-in containers such as UINavigationController, UITabBarController, and UISplitViewController all follow this pattern. iOS 5 exposed the same mechanism for custom containers.

Correct Sequence for Adding a Child

Containment is not just "add the child view as a subview." The parent-child relationship must be established first, then the child view inserted, then the transition finalized.

objectivec
1- (void)displayContentController:(UIViewController *)child {
2    [self addChildViewController:child];
3    child.view.frame = self.contentView.bounds;
4    [self.contentView addSubview:child.view];
5    [child didMoveToParentViewController:self];
6}

That sequence matters:

  • 'addChildViewController: creates the containment relationship'
  • adding child.view puts the child visually on screen
  • 'didMoveToParentViewController: tells the child the move is complete'

If you skip those lifecycle calls, you are not really using containment correctly.

Correct Sequence for Removing a Child

Removal has its own required order:

objectivec
1- (void)hideContentController:(UIViewController *)child {
2    [child willMoveToParentViewController:nil];
3    [child.view removeFromSuperview];
4    [child removeFromParentViewController];
5}

The willMoveToParentViewController:nil call is the signal that the child is about to leave the container. Only after that should you remove its view and sever the parent relationship.

Lifecycle Forwarding

With proper containment, UIKit can forward many important events from parent to child automatically, including appearance callbacks. That is a big part of the value of the API.

For example, if the parent is visible and swaps one child for another using the proper containment methods, the children can receive appearance events in a predictable way. Before iOS 5, developers often built ad hoc container systems that broke these callbacks or required lots of manual forwarding.

Switching Between Child Controllers

If your container swaps child controllers, use the containment API to keep the transition explicit:

objectivec
1- (void)swapFromController:(UIViewController *)oldController
2              toController:(UIViewController *)newController {
3    [oldController willMoveToParentViewController:nil];
4    [self addChildViewController:newController];
5
6    newController.view.frame = self.contentView.bounds;
7
8    [self transitionFromViewController:oldController
9                      toViewController:newController
10                              duration:0.25
11                               options:UIViewAnimationOptionTransitionCrossDissolve
12                            animations:nil
13                            completion:^(BOOL finished) {
14        [oldController removeFromParentViewController];
15        [newController didMoveToParentViewController:self];
16    }];
17}

This is far cleaner than manually juggling subviews without controller relationships.

Parent and Child Responsibilities

A good container draws a firm boundary:

  • the parent decides layout, navigation, and which child is active
  • the child manages its own controls, state, and screen-specific behavior

If the parent starts reaching deep into child internals, or the child tries to manage sibling controllers, the containment structure quickly becomes messy.

Common Pitfalls

The most common mistake is adding the child view without calling addChildViewController: and didMoveToParentViewController:. The UI may appear to work, but lifecycle behavior, responder handling, and future maintenance all become less predictable.

Another frequent issue is forgetting the removal calls. If you only remove the child's view and leave the controller attached, the parent still thinks it owns the child, which can create leaks and confusing state.

Finally, avoid using containment as an excuse for huge parent controllers. A container should orchestrate children, not absorb all business logic itself.

Summary

  • View controller containment lets a parent controller manage child controllers formally.
  • Add a child with addChildViewController:, insert its view, then call didMoveToParentViewController:.
  • Remove a child with willMoveToParentViewController:nil, then remove its view and parent link.
  • Use containment-aware transitions when swapping children.
  • Keep the parent responsible for composition and the child responsible for its own screen logic.

Related reading
Free course
Beginner
7 lessons
2 hours
Tackling System Design Interview Problems

A short course that equips you with the skills to approach system design interviews methodically.

Start the free course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

All Rights Reserved.