Skip to content

Commit 4534655

Browse files
rcancronguyenhuy
authored andcommitted
[ASDisplayNode] Stop infinite layout in _u_measureNodeWithBoundsIfNecessary (#1434)
We came across an infinite layout loop in `_u_measureNodeWithBoundsIfNecessary`. After requesting a layout from above, the sizes between pending and caluclated layout still do not match. We continue to prefer to use the pending layout and ask for another layout loop from above. We can’t seem to break out of this loop. The solution (thanks to Huy for the guidance) was to nil out the pending layout we get from requesting the layout from above. I was only able to reproduce this when working with a node in a `UINavigationBarItem’s` `titleView`. I think that UIKit must be doing something sneaky with setting the frame on the view. While I was not able to create a unit test to catch this issue (I tried for a long time, and can post what I’ve come up with to see if anyone has any suggestions), I was able to create a pretty simple example project that shows the behavior: https://github.com/rcancro/TextureLayoutLoopExample
1 parent c50e509 commit 4534655

File tree

1 file changed

+10
-0
lines changed

1 file changed

+10
-0
lines changed

Source/ASDisplayNode+Layout.mm

+10
Original file line numberDiff line numberDiff line change
@@ -444,6 +444,16 @@ - (void)_u_measureNodeWithBoundsIfNecessary:(CGRect)bounds
444444
__instanceLock__.lock();
445445
}
446446

447+
// If we request that our root layout we may generate a new _pendingDisplayNodeLayout.layout which has
448+
// requestedLayoutFromAbove set to NO. If the pending layout has a different constrained size than nextLayout's
449+
// and the layout sizes don't change we could end up back here asking the root to layout again causing an
450+
// infinite layout loop. Instead, we nil out the _pendingDisplayNodeLayout.layout here because it can be
451+
// considered an undesired artifact of the layout request. nextLayout will become _calculatedDisplayNodeLayout
452+
// when the pending layout transition which will be created later in this method is applied.
453+
// We will use _calculatedLayout the next time around, so requestedLayoutFromAbove will be set to YES and we
454+
// will break out of this layout loop.
455+
_pendingDisplayNodeLayout.layout = nil;
456+
447457
// Update the layout's version here because _u_setNeedsLayoutFromAbove calls __setNeedsLayout which in turn increases _layoutVersion
448458
// Failing to do this will cause the layout to be invalid immediately
449459
nextLayout.version = _layoutVersion;

0 commit comments

Comments
 (0)