From 6aa5ad7703147984e0bd9dcec803e3b9c3dc4bc6 Mon Sep 17 00:00:00 2001 From: Huy Nguyen Date: Fri, 19 May 2017 15:06:26 +0100 Subject: [PATCH] Only call -layout and -layoutDidFinish if the node is already loaded (#285) * Only call -layout and -layoutDidFinish if the node is already loaded * Minor change * Update CHANGELOG --- CHANGELOG.md | 1 + Source/ASDisplayNode+Layout.mm | 1 - Source/ASDisplayNode.mm | 18 +++++++++++++----- Source/Private/ASDisplayNodeInternal.h | 4 +++- 4 files changed, 17 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4c571f2c1f..db24296da6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,3 +27,4 @@ - [Fix] Fix a major regression in our image node contents caching. [Adlai Holler](https://github.com/Adlai-Holler) [#287](https://github.com/TextureGroup/Texture/pull/287) - [Fix] Fixed a bug where ASVideoNodeDelegate error reporting callback would crash an app because of not responding to selector. [Sergey Petrachkov](https://github.com/Petrachkov) [#291](https://github.com/TextureGroup/Texture/issues/291) - [IGListKit] Add IGListKit headers to public section of Xcode project [Michael Schneider] (https://github.com/maicki)[#286](https://github.com/TextureGroup/Texture/pull/286) +- [Layout] Ensure -layout and -layoutDidFinish are called only if a node is loaded. [Huy Nguyen](https://github.com/nguyenhuy) [#285](https://github.com/TextureGroup/Texture/pull/285) diff --git a/Source/ASDisplayNode+Layout.mm b/Source/ASDisplayNode+Layout.mm index 468b164ef5..6949199c0e 100644 --- a/Source/ASDisplayNode+Layout.mm +++ b/Source/ASDisplayNode+Layout.mm @@ -293,7 +293,6 @@ ASPrimitiveTraitCollectionDeprecatedImplementation } } -/// Needs to be called with lock held - (void)_locked_measureNodeWithBoundsIfNecessary:(CGRect)bounds { // Check if we are a subnode in a layout transition. diff --git a/Source/ASDisplayNode.mm b/Source/ASDisplayNode.mm index 58dac12d47..027c945642 100644 --- a/Source/ASDisplayNode.mm +++ b/Source/ASDisplayNode.mm @@ -902,8 +902,10 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c) ASDisplayNodeAssertThreadAffinity(self); ASDisplayNodeAssertLockUnownedByCurrentThread(__instanceLock__); + BOOL loaded = NO; { ASDN::MutexLocker l(__instanceLock__); + loaded = [self _locked_isNodeLoaded]; CGRect bounds = _threadSafeBounds; if (CGRectEqualToRect(bounds, CGRectZero)) { @@ -930,10 +932,13 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c) [self _layoutSublayouts]; - ASPerformBlockOnMainThread(^{ - [self layout]; - [self layoutDidFinish]; - }); + // Per API contract, `-layout` and `-layoutDidFinish` are called only if the node is loaded. + if (loaded) { + ASPerformBlockOnMainThread(^{ + [self layout]; + [self layoutDidFinish]; + }); + } } - (void)layoutDidFinish @@ -941,6 +946,7 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c) // Hook for subclasses ASDisplayNodeAssertMainThread(); ASDisplayNodeAssertLockUnownedByCurrentThread(__instanceLock__); + ASDisplayNodeAssertTrue(self.isNodeLoaded); } #pragma mark Calculation @@ -1082,8 +1088,10 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c) - (void)layout { + // Hook for subclasses ASDisplayNodeAssertMainThread(); - // Subclass hook + ASDisplayNodeAssertLockUnownedByCurrentThread(__instanceLock__); + ASDisplayNodeAssertTrue(self.isNodeLoaded); } #pragma mark Layout Transition diff --git a/Source/Private/ASDisplayNodeInternal.h b/Source/Private/ASDisplayNodeInternal.h index 502d381d5e..6175bd4a30 100644 --- a/Source/Private/ASDisplayNodeInternal.h +++ b/Source/Private/ASDisplayNodeInternal.h @@ -234,7 +234,9 @@ FOUNDATION_EXPORT NSString * const ASRenderingEngineDidDisplayNodesScheduledBefo - (void)__setNeedsDisplay; /** - * Called from [CALayer layoutSublayers:]. Executes the layout pass for the node + * Called whenever the node needs to layout its subnodes and, if it's already loaded, its subviews. Executes the layout pass for the node + * + * This method is thread-safe but asserts thread affinity. */ - (void)__layout;