It is easy to confuse which lines of code belong in viewDidLoad and viewWillAppear:.
In fact, I’ve seen questions on Stack Overflow and bugs on Github that always wonder, “Which is called first, viewDidLoad or viewWillAppear?” To understand which code goes where and why this question is irrelevant, we must look at the purpose of these methods and how they relate to the application as a whole.
iOS applications are made up of a number of view controllers, each representing a screen of information. For an application to communicate with a user, different view controllers are shown depending on the state of the application. For example, if a user is registering for an account, they should see a screen that allows them to enter personal information. When they are done, they can be taken to a screen that shows them their home page, whatever that might be.
The purpose of the viewWillAppear: method is to communicate these changes in screens. This alerts the view controller that is going onto the screen that it needs to be on top of its shit: making sure it has up to date information in all of its text fields, that necessary data will be accessible, proper notifications are being observed, etc. The method viewWillAppear: is triggered in response to a change in the state of the application, indicating that the view controller is becoming “active.”
The reason viewDidLoad exists – the only reason – is that it sometimes isn’t possible or efficient to configure 100% of an interface in a XIB. Sometimes, a particular property you want to set on a view isn’t available in a XIB. Sometimes, you need to modify an image before you set it as the background of a button. Sometimes, you use auto layout, and you realize that the editor for that is actually worse than writing auto layout code.
Thus, viewDidLoad is sent to a view controller right after its XIB file is loaded to allow you to perform this additional customization of views. It exists specifically for this, and only this. (In cases where you create your view programmatically with loadView, there is no reason to use viewDidLoad.)
The method viewDidLoad, then, is not to infer anything about the state of the application at the time it was called. It is simply an internal mechanism for post-processing the loading of a file. In other words, it should be considered as an extension to the XIB file itself, not a part of the application’s flow.
What does this mean? You should be changing the content of views within viewWillAppear:, not viewDidLoad. Content is the actual data (model objects) the controller passes to a view for display.
Related: To read more of Joe Conway’s work, click here.
Consider a banking application that shows your current balance. A user can tap on a button, which presents a list of nearby ATMs in a modal view controller. In order to get the list of nearby ATMs, the application must make a core location and web service request.
In this situation, a programmer could get away with requesting the list of nearby ATMs from the server in viewDidLoad. The view controller is only presented once, both viewDidLoad and viewWillAppear: will be called back to back and only once for that particular view controller instance. The net effect of the code in either of these two methods will be the same.
But this is a bad idea. Consider what would happen if you wanted to move the ATM view controller into a tab bar controller. Now, the ATM view controller – with its ATM fetching code in viewDidLoad only fetches the list of ATMs once. So you are in Atlanta on Tuesday, open up your application to look for an ATM, then check your balance. Then you travel to New York on Wednesday, re-open the banking application, and you only see ATMs in Atlanta. The view was already loaded, no need to call viewDidLoad and now you’re looking at stale data.
In fact, this situation, to me, is the biggest fallacy in writing code: the easiest way is the easiest way. Applications will change. User interfaces will change. Taking the easy way out initially leads to all kinds of subtle bugs and hardships in the future.