UIViewController fundamentals and connection with UIView created from Storyboards, Xibs or Programmatically
Regardless if you create views using storyboards
, xibs
or programmatically
, you will need a UIViewController
to manage the view hierarchy. It is part of UIKit
and fundamental for every iOS developer. One of the biggest jobs of UIViewController
is to manage the lifecycle of the view.

init()
Your custom init with or without custom parameters.
init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?)
Try to find a nib
(.xib) file and connect it to UIViewController
. There is no view created and no outlets.
init(coder:)
When you create the views of your app in a Storyboard
.
loadView()
This event creates the view that the controller manages. Load the view from a nib or programmatically created view or empty one. Using a nib
file or a storyboard
for a UIViewController
, this method shouldn’t be overridden.
Practically this is the place where you want to create your custom view programmatically. Shouldn’t be overridden when the view for the controller is created in Interface Builder
.
loadViewIfNeeded()
Loads the view controllers view if it has not already been set.
viewDidLoad()
Called after the view has been loaded into memory.
Called ones.
Place where to initialise the view, adding subviews or auto layout constraints programmatically, or to make some network request. Bounds for the view are not defined yet.
viewWillAppear(_:)
Called just before the view is about to be visible.
Called multiple times during the life of the view controller object, if screen appears(e.g.: switching tabs or app. go into the background and back).
Place to add refresh API calls, init state of animation, refresh the screen etc.
viewWillLayoutSubviews()
Called just before the view controller’s UIView
layoutSubviews
method is invoked.
Called multiple times.
This is the first place to learn the bounds of the view in the lifecycle. If you are not using constraints or Auto Layout you probably want to update the subviews here.
viewDidLayoutSubviews()
Called just after the view controllers views layoutSubviews
method is invoked.
The subviews have been set and size, position, and constraints are applied. Frames and bounds set.
Avoid using a big process if override as it is called multiple times when size changes, rotation occurs etc.
Called also when subviews of the main view are loaded, for example when cells of a table view or collection view are loaded.
viewDidAppear(_:)
Called when the view has been fully transitioned onto the screen. If some animation needs to be presented to the user this is the right place.
viewWillDisappear(_:)
Called when the view is dismissed, covered or otherwise hidden.
Saving the user data, canceling network requests, stop timer, animation, disconnect observers, notification center, revert any changes if needed…
viewDidDisappear(_:)
Called after the view was dismissed, covered or otherwise hidden.
The view is removed from view hierarchy at the moment.
didReceiveMemoryWarning()
This is called when the OS determines to free up memory for various reasons. I never used this method but assume you could use it to free up some memory or to do some last minute save.
traitCollectionDidChange(_:)
Called when the iOS interface environment changes.
For example, you might adjust the layout of the subviews of a view controller when an iPhone is rotated from portrait to landscape orientation, using custom themes. The default implementation of this method is empty.
From iOS13 it has changed a bit, so we need to be careful where to use it.
deinit
Called last when memory is deallocated.
Usually this is used to remove observers from NotificationCenter. In some cases removing the observer i would put to viewWillDisappear
. There are cases when ViewController is not deallocated but stored in property in some other class, but listens for some UI changes or API call result. This can cause crashes.
Use case 👉 Solution
If you are using NSNotificationCenter
to listen for some changes and based on those changes you manipulate with the UI, then keep in mind that if the application goes to background this notification still can arrive and force change. This can sometimes create crashes.
Solution is to subscribe for notifications with viewWillAppear
and remove with viewWillDisappear
. But it depends from situation to situation.
Outro
UIViewController
is simple for simple use cases, but can be a very complex thing if it is handles dynamic and complicated views with lots of interaction by the user. The transition mode also influences what methods will be fired and also if it contains a child viewcontroller. Child viewcontroller lifecycle could be fairly different and it is presented in next article. The link is below.
If you got to this point, thanks for reading. 🙂 If you like the content please 👏, share, subscribe, buy a coffee it means to me. If you have some suggestions or questions please feel free to comment.