Understanding the iOS ViewController Life Cycle

ViewController lifecycle is an event that has several steps from the point of creation to deletion. It is a sequence of methods as they progress.

ViewControllers play a major role in iOS applications and they create the skeleton of every application made by developers.

Let's examine the steps a view controller goes through in its lifecycle.

ios_vc_life_cycle.png

Lifecycle events order:

  • init(coder:)
  • (void)loadView
  • (void)viewDidLoad
  • (void)viewWillAppear
  • (void)viewDidAppear
  • (void)didReceiveMemoryWarning
  • (void)viewWillDisappear
  • (void)viewDidDisappear

Initializing a view controller. As is the custom in any Swift type, the view controller starts off life with an initializer. The initializer doesn’t have access to the root view, so configuring the views in the scene often occurs later in the life cycle.

While creating the views of your app in a Storyboard, init(coder:) is the method that gets called to instantiate your view controller and bring it to life. During the initial phase of a view controller, you usually allocate the resources that the view controller will need during its lifetime. In this method, you might instantiate dependencies, including subviews that you’ll add to your view programmatically. And note that init(coder:) is called only once during the life of the object, as all init methods are.

Loading a view. If the root view isn’t yet loaded, the view controller needs to load it. Wait - how could a root view already be loaded? Well, when one scene navigates to another scene, the originating view controller stays in memory. When returning to the originating view controller, its root view will display but doesn’t need to load again and the viewDidLoad method won’t be called.

The most common and recommended way for a view controller to load its root view is via the storyboard. However, a view controller can also get its root view in other ways. It can load its root view from a nib file (like a storyboard with one scene), or alternatively instantiate it in code by overriding the UIViewController’s loadView method.

After a root view and all of its subviews are loaded, the viewDidLoad method is called. This method is commonly overridden to perform any additional one-off setup that your root view requires. You could modify the properties of the root view itself. Alternatively, you could modify the properties of its subviews, or instantiate and add new subviews to the root view.

loadView is only called when the view controller is created and only when done programatically. You can override this method in order to create your views manually. This is the method that creates the view for the view controller. If you are working with storyboards or nib files, then you do not have to anything with this method and you can ignore it. Its implementation in UIViewController loads the interface from the interface file and connects all the outlets and actions for you.

viewDidLoad is only called when the view is created. Keep in mind that in this lifecycle step the view bounds are not final. Good place to init and setup objects used in the ViewController. When this method gets called, the view of the view controller has been created and you are sure that all the outlets are in place. It is also a good place where to start some background activity where you need to have the user interface in place at the end. A common case are network calls that you need to do only once when the screen is loaded. This method is called only once in the lifetime of a view controller, so you use it for things that need to happen only once.

Displaying a view. Whether the root view needed to be loaded or not, the viewWillAppear method will be called before the view displays. You override this method for tasks that require you to repeat every time a view controller comes on screen. Keep in mind that this method can be called several times for the same instance of a view controller. This event is called every time the view appears and so, there is no need to add code here, which should be executed just one time. Usually you use this method to update the user interface with data that might have changed while the view controller was not on the screen. You can also prepare the interface for animations you want to trigger when the view controller appears.

The viewDidAppear method is called after the root view is displayed. This method is commonly overridden to initiate processor-intensive work that otherwise could cause sluggishness in presenting the view. You can use it to start animations in the user interface, to start playing a video or a sound, or to start collecting data from the network. In some cases can be a good place to load data from core data and present it in the view or to start requesting data from a server.

Removing a scene’s root view. Notice in the figure that the UIViewController’s methods for displaying its root view have companion methods for removing its root view.

Before the transition to the next view controller happens and the origin view controller gets removed from screen, viewWillDisappear method gets called. You rarely need to override this method since there are few common tasks that need to be performed at this point, but you might need it.

After a view controller gets removed from the screen, viewDidDisappear method gets called. You usually override this method to stop tasks that are should not run while a view controller is not on screen. For example, you can stop listening to notifications, observing other objects properties, monitoring the device sensors or a network call that is not needed anymore.

For example, if your app navigates to a second scene, the root view for the first scene would disappear. Before this view is removed, the viewWillDisappear method is called. After the view is removed, the viewDidDisappear method is called. Override these methods to perform any final tidying up when the view disappears. Perhaps you want to stop a sound file, stop a perpetual animation, remove notification observers, or store a state.

Deinitializing a view controller. When any object is removed from memory in Swift, a special deinit method is called. Implement the view controller’s deinit method if you want to perform any additional cleanup right before this view controller is destroyed.

Releasing memory. One method that didn’t make the life cycle chart is didReceiveMemoryWarning. With modern devices, the need to free up memory is unlikely, but if your app does have high memory expectations (for example, perhaps it’s storing many images in a cache), overriding this method is where you could free up that memory.

Since view controllers perform resource management, these notifications are delivered to them through this method. In this way you can take actions to free some memory. Keep in mind that if you ignore memory warnings and the memory used by your app goes over a certain threshold, iOS will end your app means this will look like a crash to the user and should be avoided.