How lenient is the Auto Layout system when adding and removing constraints? Will it cause crashes, warnings, or will nothing happen when I use it incorrectly?
In particular, what happens when I do the following?
Imagine we have the following UIView hierarchy:
grandFather
father
target
son
grandsonuncleWe have 4 constraints defined (grandFatherConstraint, fatherConstraint, targetConstraint, and sonConstraint) which simply attaches the named view with the one right below it. The owner of the constraint is the nearest common ancestor, which happens to be the one mentioned in the constraint's name (e.g. grandFatherConstraint is owned by grandFather).
For example, grandFatherConstraint pins grandFather to father, making grandFather the nearest common ancestor of this constraint. Similarly, targetConstraint pins target to son, and target is the nearest common ancestor.
[target removeConstraint:sonConstraint])[target removeConstraint:grandFatherConstraint])[target removeConstraint:uncleConstraint])[target removeConstraint:nothingConstraint])[target removeConstraint:fatherConstraint])In all of these cases, nothing happens. The constraint is not removed.
This is expected behavior according to the removeConstraint: documentation:
Removing a constraint not held by the view has no effect.
Example: [target addConstraint:targetConstraint]
Nothing happens, it does not add the constraint a second time.
Example: [target addConstraint:newSonConstraint]
Everything will appear correct, however the owner of the constraint will not be the nearest common ancestor, which may (or may not) be the behavior you want. In other words, it will attach the constraint to the view you specified (target) rather than finding and attaching it to the nearest common ancestor (son).
The reason this may be desirable is because the owner of the constraint is significant in certain cases. From the addConstraint: documentation:
Constraints that are added to a view are said to be held by that view. The coordinate system used when evaluating the constraint is the coordinate system of the view that holds the constraint.
Example: [target addConstraint:newFatherConstraint]
This will cause a crash.
Upon installing the constraint, the following will be logged:
The view hierarchy is not prepared for the constraint: [...]
When added to a view, the constraint's items must be descendants of that view (or the view itself). This will crash if the constraint needs to be resolved before the view hierarchy is assembled. Break on -[UIView _viewHierarchyUnpreparedForConstraint:] to debug.
Upon releasing control to the main run loop, you will get a crash with the following message:
View hierarchy unprepared for constraint.
Constraint: [...]
Container hierarchy: [...]
View not found in container hierarchy: [...]
That view's superview: [...]
This is expected behavior according to the addConstraint: documentation:
The constraint may only reference the view itself or its subviews.
Example: [father addConstraint:targetConstraint]
This is an interesting scenario which isn't fully documented. When you run the above code, it will first remove the constraint from its current owner (target) and then reassign it to the new view you specified (father).
Therefore, the above code essentially becomes:
[target removeConstraint:targetConstraint]
[father addConstraint:targetConstraint]
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With