How these things work is through invalidation to remove redundancy. A view will contain information if needs to layout or not.
So calling setNeedsLayout
will just set some internal boolean value needsLayout
to true
. Once layoutIfNeeded
is called it will check this boolean value
if needsLayout {
needsLayout = false
doMagic() // Calls layoutSubviews at some point
}
Why this is designed this way is because multiple calls may invalidate layout but we want to layout it only once or as fewer times as possible.
In most cases you will not need to call setNeedsLayout
because most changes already do that for you. For instance you may change a constraint value and invalidation is done for you. All you need is to call layoutIfNeeded
and your views will update. To be more correct you don't even need to call layoutIfNeeded
as it will do that for you in the next cycle. But you will need to call it if you want the change animated for instance and you need to do that in animation block.
myViewConstraint.constant = 40.0 // Will already call setNeedsLayout
UIView.animate(withDuration: 0.3, animations: {
myView.layoutIfNeeded()
})
So changing constraints does nothing but change the information on how the view(s) should be layout. Only the call to layoutIfNeeded
will actually use those values and change layout. That is why you only need to put that in the animation block (it is not wrong to put it all in the block though).
To be fair there have been some changes where now by default (you may disable it) animate methods already layout your views by themselves so you can do with even less code but that is not the point at the moment.
So:
You do not need to call the 2 methods together to layout immediately. If the view layout is already invalidated (which is in most cases) then layoutIfNeeded
is enough. But note that setNeedsLayout
is as trivial as setting a boolean internally to true so there is no harm in calling it, just a precaution. So calling both is safer. Calling setNeedsLayout
alone will do nothing "immediately" though.
Hopefully you never need to call setNeedsLayout
. There are some complex situations where you need to explicitly invalidate layout and there are a few possible UI bugs. In all other cases this will be done for your. But note that if you come to a situation where you need to call this "it will update layout during next cycle" will not be true. Until the view layout is invalidated it will not layout at all.
I am not sure where setNeedDisplay
fits in your question (it is only in your title) but this one works the same way but is a bit more complicated. It will invalidate its content and force it to redraw, call drawRect
. This must occur during its drawing pipeline, not just anytime so you may not explicitly call it to redraw. And if you do nothing will happen (maybe crash) since it will have no context to draw on. If you override drawRect
and you resize your view it will try to cache your drawn content and use contentMode
to resize the drawing. By default it is set to scaleToFill
which means your content will be stretched as view size changes. You will need to call setNeedDisplay
in order for your drawRect
to be called again and you may redraw content accordingly.