diff --git a/Source/ASDisplayNode+Layout.mm b/Source/ASDisplayNode+Layout.mm index 6b73c1bc5..6d44b4a15 100644 --- a/Source/ASDisplayNode+Layout.mm +++ b/Source/ASDisplayNode+Layout.mm @@ -302,10 +302,10 @@ - (void)_locked_measureNodeWithBoundsIfNecessary:(CGRect)bounds } CGSize boundsSizeForLayout = ASCeilSizeValues(bounds.size); - + // Prefer _pendingDisplayNodeLayout over _calculatedDisplayNodeLayout (if exists, it's the newest) // If there is no _pending, check if _calculated is valid to reuse (avoiding recalculation below). - if (_pendingDisplayNodeLayout == nullptr) { + if (_pendingDisplayNodeLayout == nullptr || _pendingDisplayNodeLayout->version < _layoutVersion) { if (_calculatedDisplayNodeLayout->version >= _layoutVersion && (_calculatedDisplayNodeLayout->requestedLayoutFromAbove == YES || CGSizeEqualToSize(_calculatedDisplayNodeLayout->layout.size, boundsSizeForLayout))) { @@ -352,8 +352,10 @@ - (void)_locked_measureNodeWithBoundsIfNecessary:(CGRect)bounds ASLayout *layout = [self calculateLayoutThatFits:constrainedSize restrictedToSize:self.style.size relativeToParentSize:boundsSizeForLayout]; - nextLayout = std::make_shared(layout, constrainedSize, boundsSizeForLayout, version); + // Now that the constrained size of pending layout might have been reused, the layout is useless + // Release it and any orphaned subnodes it retains + _pendingDisplayNodeLayout = nullptr; } if (didCreateNewContext) { @@ -373,6 +375,9 @@ - (void)_locked_measureNodeWithBoundsIfNecessary:(CGRect)bounds // particular ASLayout object, and shouldn't loop asking again unless we have a different ASLayout. nextLayout->requestedLayoutFromAbove = YES; [self _setNeedsLayoutFromAbove]; + // Update the layout's version here because _setNeedsLayoutFromAbove calls __setNeedsLayout which in turn increases _layoutVersion + // Failing to do this will cause the layout to be invalid immediately + nextLayout->version = _layoutVersion; } // Prepare to transition to nextLayout @@ -956,7 +961,7 @@ - (void)_locked_setCalculatedDisplayNodeLayout:(std::shared_ptrlayout; displayNodeLayout->layout = [_unflattenedLayout filteredNodeLayoutTree]; } - + _calculatedDisplayNodeLayout = displayNodeLayout; } diff --git a/Source/ASDisplayNode.mm b/Source/ASDisplayNode.mm index 84862316b..2855fa91a 100644 --- a/Source/ASDisplayNode.mm +++ b/Source/ASDisplayNode.mm @@ -920,7 +920,7 @@ - (void)__layout // This method will confirm that the layout is up to date (and update if needed). // Importantly, it will also APPLY the layout to all of our subnodes if (unless parent is transitioning). [self _locked_measureNodeWithBoundsIfNecessary:bounds]; - + [self _locked_layoutPlaceholderIfNecessary]; }