In the code below, these four methods are called for layout reasoning. I'm a little confused why all of them are needed, though, and what they do differently from one another. They're used in the process to make a cell's height be dynamic with Auto Layout. (Taken from this repository from this question.)
[cell setNeedsUpdateConstraints];
[cell updateConstraintsIfNeeded];
[cell.contentView setNeedsLayout];
[cell.contentView layoutIfNeeded];
And it's from this block of code for the cell's height:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
RJTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
[cell updateFonts];
NSDictionary *dataSourceItem = [self.model.dataSource objectAtIndex:indexPath.row];
cell.titleLabel.text = [dataSourceItem valueForKey:@"title"];
cell.bodyLabel.text = [dataSourceItem valueForKey:@"body"];
cell.bodyLabel.preferredMaxLayoutWidth = tableView.bounds.size.width - (kLabelHorizontalInsets * 2.0f);
[cell setNeedsUpdateConstraints];
[cell updateConstraintsIfNeeded];
[cell.contentView setNeedsLayout];
[cell.contentView layoutIfNeeded];
CGFloat height = [cell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height;
return height;
}
But what are they doing differently? Why are they all needed?
Layout
Suppose you encapsulate your view logic in a
UIView
subclass, and call itSomeView
. This means thatSomeView
should know how to layout itself, that is, how to position some other views inside it (you can also create a view that draws itself without using any subviews, but that's beyond the needs of an average developer).This layout is done by
[SomeView layoutSubviews]
. You have an option of overriding it:but you rarely need to do so. In the dark ages of Cocoa Touch, this manual layout was widespread, but now I'd say 99% of layouts can be covered with Auto Layout.
The system needs to know when it should call
[UIView layoutSubviews]
. It's obviously done the first time you need to draw a view, but it may be also called whenever the superview frame changes. Here's a detailed explanation.So the system often calls
[view layoutIfNeeded]
. You can also call it at any time, but this will have an effect only if there is some event that has called[view setNeedsLayout]
or if you have called it manually, as in this case.Constraints
The Auto Layout (capitalized this way in the documentation) is called like that because you're leaving
[SomeView layoutSubviews]
as it is inherited fromUIView
and describe the position of your subviews instead in terms of constraints.When using Auto Layout, system will perform calls to
[view updateConstraintsIfNeeded]
at each layout pass. However, only if the flag[view setNeedsUpdateConstraints];
is set, the method calls into-updateConstraints
(which does the real job).If you don't use Auto Layout, those methods are not relevant.
You can implement it like in this example.
Your example
It's rarely necessary to call
-layoutIfNeeded
and-updateConstraintsIfNeeded
directly, because UI engine will do that automatically at each layout pass. However, in this case the author has chosen to call them immediately; this is because the resulting height is needed right now, not at some point in the future.This method of updating the cell's height seems right. Note that
cell
could be a newly created cell and thus not added into view hierarchy yet; this does not impact its ability to layout itself.Conclusion
In your custom view go with the following options, starting from the most 'universal' to most 'customized':
-updateConstraints
.-layoutSubviews
.In the code that changes something that could make your view's constraints change, call
If you need results immediately, call also
If the code changes view's frame use
and finally if you want the results immediately, call
This is why all four calls are required in this case.
Additional materials
Take a look at detailed explanation in the article Advanced Auto Layout Toolbox, objc.io issue #3