How do UITabBarController, UISplitViewController and UIPageViewController differ, and what loads when?
Predict first
Is the second tab’s view loaded before it is ever selected?
import UIKit
let t1 = UIViewController(), t2 = UIViewController()
let tab = UITabBarController()
tab.viewControllers = [t1, t2]
print(t2.isViewLoaded, tab.selectedIndex)
- true 0
- false 0
- true 1
Mental model. A tab bar is a set of drawers, each with its own stack of papers. A split view is two desks side by side that become one pile on a small table.
A tab bar controller shows one of its child controllers at a time, switched from the bar. Each tab is usually its own navigation controller, so each keeps an independent stack. Tab views are loaded lazily: only the selected tab’s view exists until the user visits another, so do not assume every tab is set up at launch. On iPhone more than five tabs collapse into a More list. A split view controller shows two or three columns (sidebar, supplementary, detail) side by side on wide screens and collapses to a single navigation stack on compact width, with delegate or column-style controls deciding what shows first. A page view controller displays one page at a time with a data source supplying the controller before and after, for swipe-based paging; it is a container too, so pages receive appearance events.
The design rules are the same for all of them: the container owns the children’s presentation, each child owns its own state, and shared state lives in a model both can read. Do not reach across containers with parent.children[n] chains; talk through a coordinator, a delegate or the model. And remember that selecting a tab again, rotating, or entering or leaving split-screen can trigger different arrangements, so test the compact and regular size classes, including collapse and expand.
Tab views are created lazily, so the unselected tab has no view yet, and the first tab is selected by default.
| Shows | Typical child | Loads children | |
|---|---|---|---|
UITabBarController | one of several top-level areas | a navigation controller each | lazily, on selection |
UISplitViewController | two or three columns, or one when compact | list, then detail | as the columns are needed |
UIPageViewController | one page, swipe to the next | a content controller per page | through the data source, on demand |
Common traps
- Setting up all tabs in the app delegate and assuming they are loaded. Unvisited tabs have no view yet.
- Putting shared state in a tab’s controller. Another tab cannot reach it cleanly. Use a model.
They might follow up with
- What does “collapse” mean in a split view? On compact width the columns become a single stack, and the primary and detail screens are pushed in order.
- When does a tab’s
viewDidLoadrun? The first time that tab’s view is needed, usually on first selection.
Related questions
- 7.4.1 How does UINavigationController manage its stack, and where do the bar items and back button come from?
- 7.3.2 What is view controller containment, and what is the correct way to embed one controller in another?
- 7.7.1 What is a trait collection, and how do size classes and trait changes drive adaptive layout?
← How does UINavigationController manage its stack, and where do the…