Question 1
View bounds and layout timing
Where do common mistakes happen when reading view bounds or forcing layout too early?
Follow-ups
- When is
viewDidLoadthe wrong place to readview.bounds?
Answer outline
Most of these bugs come from reading geometry before the system has finished a layout pass. Three patterns cover nearly all of them:
- 1.Bounds read too early: in
viewDidLoad,view.boundsis usually not final, because layout for the current orientation, safe area, and container size hasn't happened yet. Layer frames or clipping paths set from those values stay wrong until something forces a relayout. - 2.Forced layout: sprinkling
layoutIfNeeded()around to force frames into place when constraints are ambiguous or incomplete hides the real problem and adds extra layout passes. Fix the constraints instead, and remember that forcing layout inviewDidLoadstill runs against a size that may not be final. - 3.One-time safe area reads:
safeAreaInsetschange afterviewDidLoadwhen bars show or hide, on rotation, in split view, or inside a custom container, so don't cache a single read at load time. For keyboard avoidance, useview.keyboardLayoutGuide(iOS 15 and later).
Prefer Auto Layout constraints wherever you can. They stay correct across rotations, safe area changes, and container transitions without any manual pixel work.
Principles
- Treat
viewDidLoadas the place for wiring and subview creation, because final frames aren't known yet. - Read geometry and position layers in
viewDidLayoutSubviews, after callingsuper, when you need real pixels. layoutIfNeeded()is a timing tool for animating constraint changes, and it never repairs an ambiguous layout.safeAreaInsetsaren't stable at load time, so respond to changes instead of reading them once.
Geometry-dependent work in viewDidLayoutSubviews
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
// bounds now match the container and safe area for this pass
gradientLayer.frame = view.bounds
}
Change the constant, then animate the layout pass so the view moves smoothly:
Animating a constraint change with layoutIfNeeded()
heightConstraint.constant = 200
UIView.animate(withDuration: 0.3) {
self.view.layoutIfNeeded() // animates the constraint change
}
Follow-up angles
- In SwiftUI, don't assume the size you see in
onAppearis final. UseGeometryReaderoronGeometryChangewhen layout depends on the proposed size.



