A constraint change is anything that alters the underlying mathematical expression of a constraint (see Anatomy of a Constraint.). You can learn more about constraint equations in
All of the following actions change one or more constraints:
Activating or deactivating a constraint
Changing the constraint’s constant value
Changing the constraint’s priority
Removing a view from the view hierarchy
Other changes, like setting a control’s property, or modifying the view hierarchy, can also change constraints. When a change occurs, the system schedules a deferred layout pass (see The Deferred Layout Pass).
In general, you can make these changes at any time. Ideally, most constraints should be set up in Interface Builder, or programatically created by the view controller during the controller’s initial setup (for example, in
viewDidLoad). If you need to dynamically change constraints at runtime, it’s usually best to change them when the application’s state changes. For example, if you want to change a constraint in response to a button tap, make that change directly in the button’s action method.
Occasionally, you may need to batch a set of changes for performance reasons. For more information, see Batching Changes.
The Deferred Layout Pass
Instead of immediately updating the affected views’ frames, Auto Layout schedules a layout pass for the near future. This deferred pass updates the layout’s constraints and then calculates the frames for all the views in the view hierarchy.
The deferred layout pass actually involves two passes through the view hierarchy:
The update pass updates the constraints, as necessary
The layout pass repositions the view’s frames, as necessary
The system traverses the view hierarchy and calls the
updateViewConstraints method on all view controllers, and the
updateConstraints method on all views. You can override these methods to optimize changes to your constraints (see Batching Changes).
The system traverses the view hierarchy again and calls
viewWillLayoutSubviews on all view controllers, and
layout in OS X) on all views. By default, the
layoutSubviews method updates the frame of each subview with the rectangle calculated by the Auto Layout engine. You can override these methods to modify the layout (see Custom Layouts).
It is almost always cleaner and easier to update a constraint immediately after the affecting change has occurred. Deferring these changes to a later method makes the code more complex and harder to understand.
However, there are times when you may want to batch changes for performance reasons. This should only be done when changing the constraints in place is too slow, or when a view is making a number of redundant changes.
To batch a change, instead of making the change directly, call the
setNeedsUpdateConstraints method on the view holding the constraint. Then, override the view’s
updateConstraints method to modify the affected constraints.
Always call the superclasses implementation as the last step of your
updateConstraints method’s implementation.
When overriding these methods, the layout is in an inconsistent state. Some views have already been laid out. Others have not. You need to be very careful about how you modify the view hierarchy, or you can create feedback loops. The following rules should help you avoid feedback loops:
You must call the superclass’s implementation somewhere in your method.
You can safely invalidate the layout of views in your subtree; however, you must do this before you call the superclass’s implementation.
Don’t invalidate the layout of any views outside your subtree. This could create a feedback loop.
setNeedsUpdateConstraints. You have just completed an update pass. Calling this method creates a feedback loop.
setNeedsLayout. Calling this method creates a feedback loop.
Be careful about changing constraints. You don’t want to accidentally invalidate the layout of any views outside your subtree.