0

My understanding is, after execute setNeedsLayout will mark the view as "dirty" so that in the next rendering cycle, the view will be be re-layout. layoutIfNeeded will force to trigger re-layout immediately if the view is marked as "dirty".

However, even layoutIfNeeded immediately start to layout, it does not mean that the code after layoutIfNeeded will be waiting until it finishes. The render part is an async operation, it will be handled by core graphic through runloop.

myView.setNeedsLayout()
myView.layoutIfneeded()
print(myView.frame)

My point is, the printing of frame above may not always get correct frame, since the render operation is an async task, am I right?

Some context:

  1. myView is render finished.
  2. one of its subview's height constraint get changed due to some async data task.
  3. execute above setNeedsLayout and layoutIfNeed like mentioned above.
HangarRash
  • 7,314
  • 5
  • 5
  • 32
Frank
  • 624
  • 9
  • 27
  • Neither of those affect the view's frame. They lead to `layoutSubviews` being called. While `myView.frame` is not going to change, the frame of its subviews might change. – HangarRash Jul 27 '23 at 00:08
  • @HangarRash but the frame will be affect if any subview's constraint changes right? – Frank Jul 27 '23 at 00:10
  • If your goal is to ensure constraints get updated, and possibly result in the size of `myView` changing, then you probably want to use `setNeedsUpdateConstraints()` after making any change related to constraints. – HangarRash Jul 27 '23 at 00:15
  • the goal is to get accurate frame after constraint is updated. – Frank Jul 27 '23 at 00:16
  • May I ask why you need the frame? If you are using constraints, knowing the frame isn't normally needed. – HangarRash Jul 27 '23 at 00:48
  • Good question. You can assume this is an old project has highly coupled logic to update tableHeaderView using frame. – Frank Jul 27 '23 at 01:00

1 Answers1

2

am I right

Yes. If you want the frame right now, either flush the current transaction or (perhaps better) allow a cycle by doing a zero-delay asyncAfter. See How to, simply, wait for any layout in iOS? (and probably I should just be closing this question as a dupe of that one).

I should mention that an even better way is just to implement viewDidLayoutSubviews or layoutSubviews. That way, you arrive into the layout cycle at exactly the right moment to obtain any desired frame info.

matt
  • 515,959
  • 87
  • 875
  • 1,141
  • oh, the `DispatchQueue.main.asyncAfter(deadline: .now() + 0.0)` will wait till current runloop finish, even delay is 0? – Frank Jul 28 '23 at 00:03