iOS development
UIViewController
viewDidLoad
viewWillAppear
mobile app development

UIViewController viewDidLoad vs. viewWillAppear What is the proper division of labor?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

viewDidLoad and viewWillAppear are both important UIKit lifecycle hooks, but they serve different jobs. A reliable rule is that viewDidLoad is for one-time setup after the view is created, while viewWillAppear is for work that must happen every time the screen is about to become visible.

What viewDidLoad Guarantees

viewDidLoad runs after the view hierarchy has been loaded into memory. For a typical view controller, that means outlets are connected and initial UI setup can happen safely. It usually runs once for the lifetime of that controller instance.

This makes it the right place for configuration that should not be repeated:

  • Registering table or collection view cells
  • Building constraints or styling views
  • Setting delegates and data sources
  • Starting one-time fetches for static data
  • Subscribing to notifications that match the controller lifetime
swift
1import UIKit
2
3final class ProfileViewController: UIViewController {
4    @IBOutlet private weak var nameLabel: UILabel!
5    @IBOutlet private weak var avatarView: UIImageView!
6
7    override func viewDidLoad() {
8        super.viewDidLoad()
9
10        title = "Profile"
11        avatarView.layer.cornerRadius = 24
12        avatarView.clipsToBounds = true
13
14        NotificationCenter.default.addObserver(
15            self,
16            selector: #selector(handleProfileUpdated),
17            name: .profileUpdated,
18            object: nil
19        )
20    }
21
22    @objc private func handleProfileUpdated() {
23        print("Profile changed")
24    }
25}

Nothing in that block depends on the screen becoming visible right now. It is setup work, so viewDidLoad is the correct home.

What viewWillAppear Is For

viewWillAppear runs every time the controller is about to appear on screen, including after a push-pop navigation round trip. That makes it ideal for data refresh, selection updates, analytics events tied to exposure, and UI changes that may have become stale while the screen was hidden.

swift
1import UIKit
2
3final class CartViewController: UIViewController {
4    @IBOutlet private weak var totalLabel: UILabel!
5    private let cartStore = CartStore.shared
6
7    override func viewWillAppear(_ animated: Bool) {
8        super.viewWillAppear(animated)
9        totalLabel.text = cartStore.formattedTotal()
10    }
11}

If the user edits the cart on another screen and navigates back, viewDidLoad will not run again. viewWillAppear will, which is why refreshing the total belongs there.

A Practical Division of Labor

A good mental model is "create once" versus "refresh often."

Use viewDidLoad for work that prepares the controller itself. Use viewWillAppear for work that prepares the visible state of the screen.

This combined example shows the difference:

swift
1import UIKit
2
3final class OrdersViewController: UITableViewController {
4    private let service = OrderService()
5    private var orders: [Order] = []
6
7    override func viewDidLoad() {
8        super.viewDidLoad()
9        title = "Orders"
10        tableView.register(UITableViewCell.self, forCellReuseIdentifier: "Cell")
11        loadOrders()
12    }
13
14    override func viewWillAppear(_ animated: Bool) {
15        super.viewWillAppear(animated)
16        tableView.indexPathForSelectedRow.map {
17            tableView.deselectRow(at: $0, animated: true)
18        }
19    }
20
21    private func loadOrders() {
22        service.fetchOrders { [weak self] result in
23            guard let self else { return }
24            switch result {
25            case .success(let orders):
26                self.orders = orders
27                DispatchQueue.main.async {
28                    self.tableView.reloadData()
29                }
30            case .failure(let error):
31                print(error)
32            }
33        }
34    }
35}

Registering the cell and kicking off initial data loading fit viewDidLoad. Deselecting the previously tapped row each time the list reappears fits viewWillAppear.

When Another Lifecycle Method Is Better

Not every repeated task belongs in viewWillAppear. Some work is better in adjacent hooks:

  • Use viewDidAppear for actions that require the view to be fully on screen, such as presenting a dialog or starting an animation that depends on final layout.
  • Use viewWillDisappear or viewDidDisappear for cleanup, pausing video, or stopping work tied to visibility.
  • Use viewDidLayoutSubviews when you need correct final sizes before adjusting frames manually.

Choosing between these methods correctly makes controller behavior more predictable and easier to test.

Common Pitfalls

The classic mistake is putting expensive network calls in viewWillAppear without a reason. If the user navigates back and forth repeatedly, the request fires every time and can slow the app or duplicate server traffic.

Another mistake is assuming viewDidLoad runs whenever a view comes back on screen. It does not for the same controller instance, so anything that must refresh after navigation should not live there.

Developers also overload viewDidLoad with layout code that depends on final view size. At that point in the lifecycle, the layout may not be settled yet, so use a later hook if sizing matters.

Finally, avoid placing the same initialization in both methods. Repeating setup work such as observer registration can create duplicate callbacks and hard-to-debug behavior.

Summary

  • 'viewDidLoad is for one-time controller and view setup.'
  • 'viewWillAppear is for state that should refresh each time the screen is about to show.'
  • If work depends on the view being fully visible, consider viewDidAppear instead.
  • Repeated network calls in viewWillAppear are often a design smell unless the data truly must refresh.
  • A clean lifecycle split makes UIKit screens easier to reason about and maintain.

Course illustration
Course illustration

All Rights Reserved.