UIView Auto Layout life cycle
Auto Layout is among the most important topics when it comes to iOS development in general. It is extremely important to understand Auto Layout life cycle to save time and avoid naive mistakes. Lack of this information will sooner or later lead to UI glitches and performance issues in your app. This article consolidates information about the steps that every UIView
with Auto Layout enabled undergoes before being presented on a screen.
This article makes an assumption that you are familiar with Auto Layout basics. Otherwise, I suggest reading through the Apple’s Auto Layout Guide and then returning back.
Steps overview
Every UIView
with enabled Auto Layout passes 3 steps after initialization: update, layout and render. These steps do not occur in a one-way direction. It’s possible for a step to trigger any previous one or even force the whole cycle to repeat.
Update step
This step is all about calculating view frame based on its constrains. The system traverses view hierarchy bottom-up, i.e. from sub- to superview, and calls updateConstraints()
for each view [1].
Although this process happens automatically, sometimes you will need to trigger it manually. For example, you might need to immediately recalculate constraints in response to some event in your app or a change in its internal state.
setNeedsUpdateConstraints
invalidates the constraints and schedules an update for the next cycle. updateConstraintsIfNeeded
triggers updateConstraints
in place, if the constrains were previously invalidated.
Apple actually suggests against overriding updateConstraints
in Mysteries of Auto Layout WWDC session, unless you discover that changing the constraints in place is too slow. Then you will batch constraints update in updateConstraints
.
Layout step
During this step, frames of each view are updated with the rectangles calculated in the Update phase. According to High Performance Auto Layout, the process happens top-down, i.e. the system traverses views from super- to subviews and calls layoutSubviews
for each.
layoutSubviews
is the most common method to be overridden from the whole Auto Layout life cycle. You will do this when:
- Constraints are not enough to express view’s layout.
- Frames are calculated programmatically.
There are two supplementary methods in this step: setNeedsLayout
invalidate view’s layout and layoutIfNeeded
calls layoutSubviews
in place, if the layout was previously invalidated. They have exact same meaning as setNeedsUpdateConstraints
and updateConstraintsIfNeeded
do in Update step.
When overriding layoutSubviews
:
- Make sure to call
super.layoutSubviews()
. - Don’t call
setNeedsLayout
orsetNeedsUpdateConstraints
, otherwise an infinite loop will be created. - Don’t modify constraints of the views outside of the current hierarchy.
- Be careful changing constraints of views from the current hierarchy. It will trigger an Update step followed by another Layout step, potentially creating an infinite loop.
Rendering
This step is responsible for bringing pixels onto the screen. By default, UIView
passes all the work to a backing CALayer
that contains a pixel bitmap of the current view state. This step is independent of whether Auto Layout is enabled for a view or not. Same as with the layout step, rendering happens top-down [1].
The key method here is drawRect
. Unless you are doing custom OpenGL ES, Core Graphics or UIKit drawing, there is no need to override this method.
All changes like background color, adding subviews etc. are drawn automatically. Most of the time you can compose UI from different views and layers, and don’t need to override drawRect
.
What about UIViewControllers
Methods from steps 1 and 2 have their counterparts for the view controllers:
- Update phase:
updateViewConstraints
. - Layout phase:
viewWillLayoutSubviews
/viewDidLayoutSubviews
.
Method viewDidLayoutSubviews
is the most important among all. It is called to notify view controller that its view has finished the Layout step, i.e. it’s bounds have changed. This is an opportunity to make changes to a view after it has laid out its subviews, but before it becomes visible on the screen.
Intrinsic Content Size
Intrinsic content size is a natural size of a view based on its content. For example, an image view’s intrinsic content size is a size of it’s image.
Here are two tricks that will help you to simplify the layout and reduce the number of constraints:
- It’s a good practice to override
intrinsicContentSize
for custom views, returning an appropriate size for their content. - If a view has an intrinsic size only for one dimension, you should still override
intrinsicContentSize
and returnUIViewNoIntrinsicMetric
for the unknown dimension.
Alignment Rectangle
Alignment rectangles are used by the Auto Layout engine to position views, thus separating their frames from the content being layed out. It’s important to note that the intrinsic content size refers to the alignment rectangle rather than the frame.
By default, view’s alignment rectangle equals to its frame modified by alignmentRectInsets
. To get a better control over the alignment rectangle, you can override alignmentRect(forFrame:)
and frame(forAlignmentRect:)
. These two methods must be an inverse of each other.
Let’s see how alignment rectangle affects Auto Layout positioning by example.
The circles above are both image views that are centered in the same way by means of Auto Layout. The only difference is how the shadow is added to the circle. The shadow of the left circle is a part of its image, i.e. the image has a drop shadow effect. The right view has a shadow added by means of UIKit and its image contains only a circle.
The key to understanding their positioning is the difference in alignment rectangles. Since shadow is a part of the left view’s image, it is also a part of its alignment rectangle. Thus, the center of alignment rectangle does not match with the circle center.
Conversely, the right view has a shadow added by means of UIKit. Its alignment rectangle does not include the shadow, which means that the circle center and the alignment rectangle center are equal.
Wrapping up
We covered the most important aspect of the three steps every UIView
with Auto Layout enabled undergoes, before being presented on the screen. Namely: constraints update, layout and render (or display). Additionally, we discussed what are intrinsic content size and alignment rectangle and how they relate.
The topics we discussed are absolute minimum you should know about the Auto Layout life cycle. These details are easy to forget when not working with Auto Layout for some time, so it is handful to keep them consolidated to freshen your knowledge at a glance.
Further Reading
Thanks for reading!
If you enjoyed this post, be sure to follow me on Twitter to keep up with the new content. There I write daily on iOS development, programming, and Swift.