Skip to content
Prepare to Grow

UIKit Development

Introduction to UIKit and the View Controller Lifecycle

Learn UIKit's object-based interface model and place work in the correct view-controller lifecycle method.

Intermediate6 min read2 guided activities

Before you begin

What you will understand

  • Explain the roles of views, view controllers, and container controllers.
  • Distinguish one-time setup from appearance-time updates.
  • Trace the main view lifecycle callbacks.
  • Avoid lifecycle code that repeats work or leaks resources.
01

Learning stage

Concept Explanation

UIKit is an imperative, object-oriented UI framework. UIView objects draw content and receive interaction, while UIViewController objects coordinate a view hierarchy with application state and navigation. UIKit supplies container controllers such as UINavigationController and UITabBarController so screens participate in familiar platform behavior.

A controller's view loads lazily. Use loadView to create the root hierarchy programmatically and viewDidLoad for one-time configuration after loading. Use viewWillAppear or viewIsAppearing for information that must be refreshed for each appearance; at viewIsAppearing time the hierarchy has current geometry, safe-area insets, and traits.

Appearance and layout are different events. Layout callbacks can run many times, so they should not trigger requests or duplicate constraints. Pair temporary work with disappearance or deinitialization: cancel observation, stop work that no longer benefits the user, and keep business state outside the controller when it must outlive the screen.

  • UIView: a visual, interactive object in the hierarchy.
  • UIViewController: coordinates one root view hierarchy.
  • loadView: creates a programmatic root view.
  • viewDidLoad: performs one-time view setup.
  • viewIsAppearing: refreshes appearance-dependent content with current geometry.
  • Container controller: manages relationships between child controllers.
02

Learning stage

Syntax & Examples

This controller separates one-time construction from work that belongs to each appearance.

ProfileViewController.swiftswift
import UIKit

final class ProfileViewController: UIViewController {
  private let nameLabel = UILabel()
  private var refreshTask: Task<Void, Never>?

  override func loadView() {
    let root = UIView()
    root.backgroundColor = .systemBackground
    nameLabel.translatesAutoresizingMaskIntoConstraints = false
    root.addSubview(nameLabel)
    NSLayoutConstraint.activate([
      nameLabel.centerXAnchor.constraint(equalTo: root.centerXAnchor),
      nameLabel.centerYAnchor.constraint(equalTo: root.centerYAnchor)
    ])
    view = root
  }

  override func viewDidLoad() {
    super.viewDidLoad()
    title = "Profile"
    nameLabel.font = .preferredFont(forTextStyle: .title2)
  }

  override func viewIsAppearing(_ animated: Bool) {
    super.viewIsAppearing(animated)
    refreshTask?.cancel()
    refreshTask = Task { [weak self] in
      self?.nameLabel.text = await ProfileStore.shared.displayName()
    }
  }

  deinit { refreshTask?.cancel() }
}
The hierarchy is created once, styling is configured once, and changing profile data is refreshed as the screen appears.
03

Learning stage

Real-World Usage

Connect the UIKit concept to complete, maintainable application features.

  • Refresh a profile after an edit screen is dismissed.
  • Start and stop camera or media behavior with visibility.
  • React to current safe-area and trait values during appearance.
  • Embed content controllers in navigation, tab, or custom containers.
04

Learning stage

Common Mistakes

Identify lifecycle, ownership, identity, layout, accessibility, and user-experience risks.

  • Starting recurring work every time viewDidAppear runs without cancellation.
  • Creating constraints inside viewDidLayoutSubviews.
  • Assuming viewDidLoad means the screen is visible.
  • Reading final geometry before the controller has appeared.
  • Putting durable domain state only in a view controller.
05

Learning stage

Practice Exercises

Build the behavior in a small Xcode project and inspect it across realistic states.

Activity 1

Trace lifecycle events

Create two controllers in a navigation stack and log their load, appearance, layout, disappearance, and deinitialization callbacks.

Hint: Push, pop, rotate, and switch away from the app; note which callbacks repeat.

Activity 2

Place work deliberately

Classify title setup, profile refresh, animation start, constraint creation, and task cancellation by the lifecycle method that should own each.

Hint: Ask whether the work is one-time, appearance-specific, geometry-specific, or cleanup.

06

Learning stage

Knowledge Check

Answer each question before revealing the explanation.

QUESTION 1

Where should one-time setup after a controller's view loads usually go?

  1. A.viewDidLoad
  2. B.viewDidAppear
  3. C.viewDidLayoutSubviews
  4. D.deinit
Reveal answer

viewDidLoad

It runs after the hierarchy is loaded and is appropriate for setup that should not repeat on every appearance.

QUESTION 2

Why is viewIsAppearing useful for appearance-time UI updates?

Reveal answer

The view is in the hierarchy and has current geometry, safe-area insets, and traits.

It runs once per appearance transition after those environment values are established.

07

Learning stage

Interview Preparation

Explain the design in terms of lifecycle, identity, ownership, system behavior, and trade-offs.

How do you decide where work belongs in a UIViewController lifecycle?

Short answer: Separate hierarchy creation, one-time configuration, per-appearance refresh, repeated layout, and cleanup.

Explore the detailed answer

I create a programmatic hierarchy in loadView, configure it in viewDidLoad, refresh visibility-dependent data in an appearance callback, and reserve layout callbacks for geometry work. Any observation or asynchronous work has an explicit lifetime and cancellation point.

Possible follow-ups

  • • When can viewDidLoad run without the view appearing?
  • • Why should network work avoid layout callbacks?
08

Learning stage

Key Takeaways

UIKit screens are long-lived collaborating objects with an explicit lifecycle. Correct placement of construction, refresh, layout, and cleanup work keeps them predictable.

  • Views render and interact; controllers coordinate.
  • Views load lazily.
  • Use viewDidLoad for one-time setup.
  • Use appearance callbacks for visibility-dependent updates.
  • Treat layout callbacks as repeatable and keep lifetimes explicit.