Object Life Cycle: UIViewController

Software

When programming in iOS, it’s inevitable that you’ll need to subclass UIViewController. These subclasses contain all the logic that makes your apps look and behave as they should. It’s hard to set up a subclass without knowing which overridden methods will get called and when. To remedy this potential confusion, this post will take a look at the life cycle of a UIViewController.

A Simple Set Up

VCLifeCycle

This is what our set up looks like in Interface Builder. We will be examining Scene B. This controller is part of a UINavigationController stack and contains another scene via a container view. Like most controllers, Scene B’s controller has references to objects created in Interface Builder using IBOutlet properties.

Controller A Pushes to Controller B

When Scene A triggers a ‘show’ segue, these overridden methods are called on Scene B’s controller in the following order:

  1. initWithCoder:
    • When using storyboards, the controller is initialized with this method, not with the init or initWithNibName:bundle: methods.
  2. awakeFromNib
  3. willMoveToParentViewController:
    • The controller that is passed with this call is the UINavigationController.
  4. prefersStatusBarHidden
  5. preferredStatusBarUpdateAnimation
  6. loadView
    • UIViewController‘s loadView function assigns all objects with ‘Referencing Outlets’ (aka IBOutlets) in Interface Builder to their corresponding IBOutlet properties. If you need access to these IBOutlet objects in this function, call super first.
  7. prepareForSegue:sender:
    • This call allows us to inspect the UIStoryboardEmbedSegue that embeds the smaller scene in Scene B’s container view.
  8. viewDidLoad
    • This method is usually where most of a controller’s set up happens. Note that all of our IBOutlets have been connected, but our views have not yet been laid out.
  9. extendedLayoutIncludesOpaqueBars
  10. edgesForExtendedLayout
  11. viewWillAppear:
  12. extendedLayoutIncludesOpaqueBars
  13. edgesForExtendedLayout
  14. updateViewConstraints
  15. viewWillLayoutSubviews
  16. viewDidLayoutSubviews
  17. Animation
    • The animation that transitions from Scene A to Scene B runs. Step 18 does not happen until the animation finishes.
  18. viewDidAppear:
  19. didMoveToParentViewController:
    • This call concludes the process started on step 2. Here we receive the same instance of UINavigationController.
  20. updateViewConstraints
  21. viewWillLayoutSubviews
  22. viewDidLayoutSubviews

This answers some questions about which calls come first, in addition to exposing some interesting quirks. Several calls are apparently happening more than once. The scene’s view performs its layout twice, once before and once after its animation. The scene also redundantly queries the controller about the extended layout.

Controller B Pushes to Controller C

Similar to our last transition, Scene B now triggers a ‘show’ segue. The controller’s overridden methods are called in the following order:

  1. prepareForSegue:sender:
    • This call allows us to inspect the UIStoryboardShowSegue object that will segue to Scene C.
  2. viewWillDisappear:
  3. updateViewConstraints
  4. Animation
    • The animation that transitions from Scene B to Scene C runs. Step 5 does not happen until the animation finishes.
  5. viewDidDisappear:

No surprises here. We’re only getting a few calls and they all seem to make sense in this context.

Controller C Pops to Controller B

Now that we’ve gone past Scene B, we’re going to come back. Scene B is being loaded via a UINavigationController pop (as opposed to the push in the first example). We get the following calls:

  1. prefersStatusBarHidden
  2. preferredStatusBarUpdateAnimation
  3. extendedLayoutIncludesOpaqueBars
  4. edgesForExtendedLayout
  5. viewWillAppear:
  6. extendedLayoutIncludesOpaqueBars
  7. edgesForExtendedLayout
  8. updateViewConstraints
  9. viewWillLayoutSubviews
  10. viewDidLayoutSubviews
  11. Animation
    • The animation that transitions from Scene C to Scene B runs. Step 12 does not happen until the animation finishes.
  12. viewDidAppear:
  13. updateViewConstraints
  14. viewWillLayoutSubviews
  15. viewDidLayoutSubviews

These calls and their ordering should be pretty familiar from the first transition. Notably absent are some of the one-time set up steps. The controller is still inside the UINavigationController so there are no calls concerning the parent controller.

Controller B Pops to Controller A

We’re now done with our Scene B controller. Popping it off of the UINavigationController stack gives us the following calls:

  1. willMoveToParentViewController:
    • The view controller argument in this call is nil. This tells us that Scene B is being removed from the hierarchy.
  2. viewWillDisappear:
  3. updateViewConstraints
  4. viewDidDisappear:
  5. Animation
    • The animation that transitions from Scene B to Scene A runs. Step 6 does not happen until the animation finishes.
  6. didMoveToParentViewController:
    • This call concludes the process started on step 1. Here we receive the same nil argument.
  7. dealloc

Similar to the second transition, this transition seems pretty straight-forward. After the controller is removed from the hierarchy its dealloc method is called like any other NSObject.

See For Yourself

The code that I used to run this test is up on my github here. Feel free to try it yourself, and insert any other steps you would use in your own controllers.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s