5 Mar 2014

The hard life of a View Controller

Just a few notes about the View Controller's lifecycle. The lifecycle is mainly composed of a series of messages that are sent to UIViewController in order to notify it that something "view-related" has just happened or is about to.
iOS apps View Controllers are declared as sub-classes of UIViewController class, so we can override UIViewController's lifecycle methods to properly manage app's behaviour (caveat: don't forget to let the super-class method run when overriding). Let's have a look at the most important lifecycle methods we can override.

Once a view hierarchy has been loaded in memory and the outlets have been set, viewDidLoad is called. This method is a great place to put initialisation code in, even better than the init method, because when this method is called outlets have been already set and we can "talk" to view elements before they appear on the screen. viewDidLoad is called only once in the lifetime of a View Controller. This method is called when the geometry of the view is not set yet, so we'd never want to put "geometry-dependent" code in this method.

Just before the view appears on the screen, viewWillAppear: method is called. While a view is loaded once, it can appear and disappear from the screen many times, so it's not a good idea to put here "one-time" initialisation code, because naturally it would be called multiple times. Best code to put in this method is the one for "syncing" the view (about to appear) with the model data that might have changed while the view was off-screen. Geometry information are set when this method is called, so it can be fine to run some "geometry-related" code in this method but better be aware that view geometry can immediately change after this method has been called (e.g. if the user rotates the device).

This gets called to notify that the view is just about to disappear, so this is a good place for light "cleanup" code and resource releasing, preparing to "disappear". For example this method can be useful to run code that saves the state of the app, so that it can be restored when the view will be back on screen.

viewWillLayoutSubviews and viewDidLayoutSubviews
The first one is called just after the geometry of the view's frame has changed and the subviews elements are about to be laid out again. In between "will" and "did" methods iOS "auto-layout" happens, trying to do its best to adapt subviews to the new geometry (e.g. if the user rotates the device).
So, these are THE places to run "geometry-related" code.

didReceiveMemoryWarning (not strictly related to the VC lifecycle)
Good management of resources is especially important in small devices, so this method is called when the system determines that the amount of available memory is small and that is necessary to release some resources. Overriding this method can allow us to release some more resources, for example, if the view is currently off-screen we should set to nil "strong" pointers to objects that can be recreated later when the view will be back on screen, especially pointers to sounds and images objects.

This method is different in that it is sent to all objects "awaken from nib", not just the View controller. It's called after every objects in the nib file has been loaded and initialised, before viewDidLoad.
If a View Controller is allocated and initialised in code and not from a nib, that is, using the designated initialiser initWithNibName:bundle:. In this case is necessary to put the custom code we would have put in the awakeFromNib also in this initialisation method, because if the View Controller is not set in that nib file it doesn't get awakeFromNib message.

More info on "nib" files here.