Reputation: 1334
When programmatically creating layouts, I follow Apple's advice: override -updateConstraints, add custom constraints, and call -setNeedsUpdateConstraints once subviews have been added to the view. My typical setup looks like this:
- (void)setupViews
{
//Style View
//Add gesture recognizers
//Add Subviews
[self setNeedsUpdateConstraints];
}
- (void)updateConstraints
{
//Add custom constraints
[super updateConstraints];
}
The problem
There are occasions when -updateConstraints gets fired multiple times (for example, when a view's controller is presented or pushed w/ animation). The problem here is that each constraint added gets re-added. This becomes a serious problem when trying to on-demand change the constant of an added constraint, since there are two of the original constraint that subsequently conflict with each other. I imagine that even when you aren't manipulating the constraints after creating them, having double what you doesn't seem good.
Potential solutions
1 - Remove all constraints effecting the view before applying them in -updateConstraints:
- (void)updateConstraints
{
//Remove all constraints affecting view & subviews
//Add custom constraints
[super updateConstraints];
}
2 - Set a layout flag & check against it before adding custom constraints:
- (void)updateConstraints
{
if (self.didAddConstraints) {
[super updateConstraints];
return;
}
//Add custom constraints
self.didAddConstraints = YES;
[super updateConstraints];
}
3 - Don't worry about doubling up on constraints, and whenever changing a constant is needed, only remove that constraint before re-adding.
3 - Something awesome that I haven't thought of.
What's the best practice here?
Upvotes: 19
Views: 8548
Reputation: 4168
Short answer: Potential solution number 2.
Removing and reapplying all constraints may become costly as the layout becomes more complex. Besides, if your layout is stateful, you'd have more problems.
Doubling constraints is very inefficient, you can never know how many times updateConstraints
might be called.
As this blog post shows, using a flag is the simplest, most efficient way of dealing with this problem. That is how I deal with it myself.
As a side note, you mention of there existing an awesome way that you have not thought of yet. Most of the times, the simplest way IS the most awesome way. :)
Upvotes: 17
Reputation:
This kind of tracking could be done too, for the initial setup. In most cases.
override func updateConstraints() {
if constraints.count == 0 {
let views = ["textField": textField]
addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|-0-[textField]-0-|", options: [], metrics: nil, views: views))
addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|-0-[textField]-0-|", options: [], metrics: nil, views: views))
}
super.updateConstraints()
}
Upvotes: 0