1
votes

As I know, -setNeedsLayout method only set the flag to the view, to layout subviews on the next update cycle. But layoutIfNeeded calls layoutSubviews method immediately, not waiting the next update cycle.

But when I call -setNeedsLayout on the view, -layoutSubviews method executes immediately. As I understand, next update cycle should run only with user interaction or view's frame changes. Am I wrong somewhere? Maybe setNeedsLayout calls update cycle? But when? And how it will work? if I call for example 3 methods

[self setNeedsLayout];
[self setNeedsUpdateConstraints];
[self setNeedsDisplay];
1
Watch developer.apple.com/videos/play/wwdc2015/218 . It explains the entire flow. It’s companion developer.apple.com/videos/play/wwdc2015/219 may be useful tooWarren Burton
Thank you very much! I'll watch it!iamirzhan

1 Answers

2
votes

I've finally found an answer. Thanks to warren-burton, to share a link of WWDC presentation, it really helps.

To answer to my question, we should firstly understand what really is the "Update cycle". It consist of three parts. Constraints part(to update all constraints), layout part(to set all frames) and drawing part(to draw a view on the screen). The main reason of misunderstanding in my question was that I don't know that

THE UPDATE CYCLE IS A LOOP

This loop is always running. That means potentially update cycle can run about 120 times per second. It was really bad performance if we would update constraints, layout and redraw 120 times every second. To avoid this problem there are a flags to update layout, update constraints and drawing. So, each update cycle the system checks in each part if it is necessary to call corresponding methods. And methods like updateConstraints(), layoutSubviews() and drawRect() calls only if the corresponding flag is on.

Can we affect these flags?

Yes, we can set the needed flag to true via setNeedsUpdateConstraints(), setNeedsLayout() and setNeedsDisplay() methods. So, if we call setNeedsLayout() method, the flag is set to true, and the layout will be updated in next update cycle.

enter image description here

Why after setNeedsLayout layoutsSubviews method executes immediately

It never executes immediately. It only seems to user that update cycle runs right after calling setNeedsLayout, because update cycle runs very fast and frequently. The good example to understand is a changing constraint constant.

print(label.frame.height) // 100
labelHeightConstraint.constant = 200
print(label.frame.height) // 100

After we change the constraint, the system recalculates the frames and call the setNeedsLayout() to update frames in next update cycle. If you print the height of frame, it would be old, cause the update cycle doesn't occur yet. To see the calculated frame, you should force call the method immediately via layoutIfNeeded() method

print(label.frame.height) // 100
labelHeightConstraint.constant = 200
layoutIfNeeded()
print(label.frame.height) // 200