In what order do updateConstraints, the controller hooks and layoutSubviews run, and where should each kind of work go?
Predict first
What order do the controller and view hooks run after the two requests?
import UIKit
var log: [String] = []
final class V: UIView {
override func layoutSubviews() { log.append("V.layoutSubviews"); super.layoutSubviews() }
override func updateConstraints() { log.append("V.updateConstraints"); super.updateConstraints() }
}
final class VC: UIViewController {
override func loadView() { view = V() }
override func updateViewConstraints() { log.append("updateViewConstraints"); super.updateViewConstraints() }
override func viewWillLayoutSubviews() { log.append("viewWillLayoutSubviews") }
override func viewDidLayoutSubviews() { log.append("viewDidLayoutSubviews") }
}
let w = UIWindow(frame: CGRect(x: 0, y: 0, width: 390, height: 844))
let vc = VC()
w.rootViewController = vc
w.makeKeyAndVisible()
RunLoop.current.run(until: Date().addingTimeInterval(0.3))
log = []
vc.view.setNeedsLayout()
vc.view.layoutIfNeeded()
print(log.joined(separator: ", "))
log = []
vc.view.setNeedsUpdateConstraints()
vc.view.layoutIfNeeded()
print(log.joined(separator: ", "))
- viewWillLayoutSubviews, V.layoutSubviews, viewDidLayoutSubviews / updateViewConstraints, V.updateConstraints, viewWillLayoutSubviews, V.layoutSubviews, viewDidLayoutSubviews
- V.layoutSubviews only for both
- updateViewConstraints, viewWillLayoutSubviews, V.updateConstraints, V.layoutSubviews
Mental model. The passes are a restaurant kitchen: first the menu is revised (constraints), then plates are laid out (layout), then they are decorated (display), and each stage only starts when it has been marked dirty.
Auto Layout runs as separate passes, each triggered by its own flag. setNeedsUpdateConstraints() schedules the constraint pass, where updateViewConstraints() (controller) and updateConstraints() (view) change constraints; setNeedsLayout() schedules the layout pass. In the check, after setNeedsLayout the order is viewWillLayoutSubviews, the view's layoutSubviews, viewDidLayoutSubviews; after setNeedsUpdateConstraints the constraint pass comes first (updateViewConstraints then the view's updateConstraints) and the same three layout steps follow. A constraint change also triggers layout, and layoutIfNeeded() runs a pending pass immediately, which is what you call inside an animation block (Q278).
Put work in the hook that matches its inputs. Structural constraint changes that depend on state belong in updateConstraints (it coalesces many requests into one), cheap activate or deactivate switches can be done directly. viewWillLayoutSubviews is the controller's chance to adjust things before its view lays out (for example setting a content inset from the final bounds), viewDidLayoutSubviews is the first moment the children have final frames (read them to position overlays), and layoutSubviews is for a custom view's manual frames. Layout can run many times (rotation, safe-area changes, scrolling in some containers), so these methods must be idempotent and cheap, and must not request another layout unconditionally, which loops. I did not assert the very first appearance order because it differs between a real app and a headless run; the post-launch passes are the stable part.
Constraint pass first when requested, then will-layout, the view layout, did-layout.
Common traps
- Reading final frames in
viewDidLoadorviewWillLayoutSubviews. They are final only inviewDidLayoutSubviewsor later. - Calling
setNeedsLayoutunconditionally insidelayoutSubviews. It schedules another pass forever.
They might follow up with
- Is
updateConstraintsneeded in modern code? Often not; activate and deactivate constraint sets directly, and use it when many triggers must coalesce. - Where does
viewIsAppearingfit? AfterviewWillAppearwith up-to-date geometry (Q240).
Related questions
- 7.3.1 What is the view controller lifecycle, and what belongs in each method?
- 9.1.1 How does Auto Layout work, and what are intrinsic size, content hugging, compression resistance, priorities…
- 9.1.2 What is the difference between layoutSubviews and draw(_:), and what triggers each?
Which UIKit patterns keep a view controller alive after it is… →