UIViewController
& Advanced PatternsUIViewController
owns a root view and orchestrates:
init(coder:)
/ init(nibName:bundle:)
loadView()
viewDidLoad()
viewWillAppear(_ animated: Bool)
viewWillLayoutSubviews()
viewDidLayoutSubviews()
viewDidAppear(_ animated: Bool)
viewWillDisappear(_ animated: Bool)
viewDidDisappear(_ animated: Bool)
deinit
class GreetingViewController: UIViewController {
override func loadView() {
let root = UIView()
root.backgroundColor = .systemBackground
let label = UILabel()
label.text = "Hello, UIKit!"
label.font = .systemFont(ofSize: 32, weight: .bold)
label.translatesAutoresizingMaskIntoConstraints = false
root.addSubview(label)
NSLayoutConstraint.activate([
label.centerXAnchor.constraint(equalTo: root.centerXAnchor),
label.centerYAnchor.constraint(equalTo: root.centerYAnchor)
])
self.view = root
}
override func viewDidLoad() {
super.viewDidLoad()
print("View finished loading")
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
print("Will appear, animated =", animated)
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
print("Did appear, animated =", animated)
}
}
loadView()
— create/assign root view; must set self.view
.viewDidLoad()
— one-time setup detached from geometry (e.g. data bindings).didReceiveMemoryWarning()
(deprecated iOS 13) — purge caches/non-visible subviews.viewWillAppear(_ animated: Bool)
— refresh UI; animated
signals transition style.viewDidAppear(_ animated: Bool)
— start heavy animations, analytics.viewWillDisappear/DidDisappear
— pause timers, save edits, stop AV playback.viewWillLayoutSubviews()
— tweak constraints before AutoLayout finalizes.viewDidLayoutSubviews()
— update scrollView contentSize, gradient layers, etc.present(_ viewControllerToPresent: UIViewController,
animated: Bool,
completion: (() -> Void)? = nil)
• viewControllerToPresent — modal target.
• animated — true
for animated transition.
• completion — runs after animation ends.
dismiss(animated:completion:)
navigationController?.pushViewController(_:animated:)
performSegue(withIdentifier:sender:)
& prepare(for:sender:)
addChild(_ childController: UIViewController)
willMove(toParent:)
/ didMove(toParent:)
removeFromParent()
let editorVC = TextEditorViewController()
editorVC.modalPresentationStyle = .formSheet
present(editorVC, animated: true)
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "showDetail",
let detail = segue.destination as? DetailViewController,
let note = sender as? Note {
detail.note = note
}
}
class SplitContainerController: UIViewController {
private let master = MasterViewController()
private let detail = DetailViewController()
override func viewDidLoad() {
super.viewDidLoad()
add(master, constrainedTo: view.leadingAnchor)
add(detail, constrainedTo: view.trailingAnchor)
}
private func add(_ child: UIViewController, constrainedTo anchor: NSLayoutXAxisAnchor) {
addChild(child)
child.view.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(child.view)
NSLayoutConstraint.activate([
child.view.topAnchor.constraint(equalTo: view.topAnchor),
child.view.bottomAnchor.constraint(equalTo: view.bottomAnchor),
child.view.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 0.5),
child.view.leadingAnchor.constraint(equalTo: anchor)
])
child.didMove(toParent: self)
}
}
viewWillAppear(_:)
if data may change while hidden.viewDidLayoutSubviews()
if it triggers another layout pass.deinit
or viewWillDisappear(_:)
to prevent leaks.loadView
→ viewDidLoad
→ viewWillAppear
→ viewDidAppear
→ viewWillDisappear
→ viewDidDisappear
present(_:animated:completion:)
UINavigationController
, UITabBarController
performSegue
, prepare(for:sender:)
addChild
, didMove
, removeFromParent
viewWillTransition(to:with:)
preferredStatusBarStyle
• Apple Developer Documentation → UIViewController
• Advanced iOS App Architecture (Objc.io)
• WWDC Sessions: “View Controller Advanced Techniques”, “State Restoration in Depth”.