From 271f288a199f2c3795c63a15274b5ead7c05b7c6 Mon Sep 17 00:00:00 2001 From: Scott Goodson Date: Sun, 6 Dec 2015 15:04:47 -0800 Subject: [PATCH] Polish ASHierarchyState implementation, fix old comment typos, work on test breakages. --- AsyncDisplayKit/ASDisplayNode.mm | 59 ++++++++++++++----- .../Private/ASDisplayNode+AsyncDisplay.mm | 2 +- AsyncDisplayKitTests/ASDisplayNodeTests.m | 2 +- AsyncDisplayKitTests/ASSnapshotTestCase.mm | 2 + 4 files changed, 47 insertions(+), 18 deletions(-) diff --git a/AsyncDisplayKit/ASDisplayNode.mm b/AsyncDisplayKit/ASDisplayNode.mm index e7d266836c..8924e2b5b5 100644 --- a/AsyncDisplayKit/ASDisplayNode.mm +++ b/AsyncDisplayKit/ASDisplayNode.mm @@ -633,12 +633,14 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c) - (void)setShouldRasterizeDescendants:(BOOL)shouldRasterize { ASDisplayNodeAssertThreadAffinity(self); - ASDN::MutexLocker l(_propertyLock); - - if (_flags.shouldRasterizeDescendants == shouldRasterize) - return; - - _flags.shouldRasterizeDescendants = shouldRasterize; + { + ASDN::MutexLocker l(_propertyLock); + + if (_flags.shouldRasterizeDescendants == shouldRasterize) + return; + + _flags.shouldRasterizeDescendants = shouldRasterize; + } if (self.isNodeLoaded) { // Recursively tear down or build up subnodes. @@ -661,6 +663,14 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c) // nodes that have shouldBypassEnsureDisplay set (such as image nodes) so they are rasterized. [self recursivelyDisplayImmediately]; } + } else { + ASDisplayNodePerformBlockOnEverySubnode(self, ^(ASDisplayNode *node) { + if (shouldRasterize) { + [node enterHierarchyState:ASHierarchyStateRasterized]; + } else { + [node exitHierarchyState:ASHierarchyStateRasterized]; + } + }); } } @@ -962,7 +972,7 @@ static bool disableNotificationsForMovingBetweenParents(ASDisplayNode *from, ASD [oldSubnode removeFromSupernode]; [_subnodes insertObject:subnode atIndex:subnodeIndex]; - // Don't bother inserting the view/layer if in a rasterized subtree, becuase there are no layers in the hierarchy and none of this could possibly work. + // Don't bother inserting the view/layer if in a rasterized subtree, because there are no layers in the hierarchy and none of this could possibly work. if (!_flags.shouldRasterizeDescendants && [self __shouldLoadViewOrLayer]) { if (_layer) { ASDisplayNodeCAssertMainThread(); @@ -1083,7 +1093,7 @@ static NSInteger incrementIfFound(NSInteger i) { NSInteger aboveSubnodeIndex = [_subnodes indexOfObjectIdenticalTo:above]; NSInteger aboveSublayerIndex = NSNotFound; - // Don't bother figuring out the sublayerIndex if in a rasterized subtree, becuase there are no layers in the hierarchy and none of this could possibly work. + // Don't bother figuring out the sublayerIndex if in a rasterized subtree, because there are no layers in the hierarchy and none of this could possibly work. if (!_flags.shouldRasterizeDescendants && [self __shouldLoadViewOrLayer]) { if (_layer) { aboveSublayerIndex = [_layer.sublayers indexOfObjectIdenticalTo:above.layer]; @@ -1336,16 +1346,33 @@ static NSInteger incrementIfFound(NSInteger i) { return _supernode; } -- (void)__setSupernode:(ASDisplayNode *)supernode +- (void)__setSupernode:(ASDisplayNode *)newSupernode { - ASDN::MutexLocker l(_propertyLock); - if (_supernode != supernode) { - ASHierarchyState oldHierarchyState = _supernode.hierarchyState; - _supernode = supernode; - if (_supernode) { - [self enterHierarchyState:_supernode.hierarchyState]; + BOOL supernodeDidChange = NO; + ASDisplayNode *oldSupernode = nil; + { + ASDN::MutexLocker l(_propertyLock); + if (_supernode != newSupernode) { + oldSupernode = _supernode; // Access supernode properties outside of lock to avoid remote chance of deadlock, + // in case supernode implementation must access one of our properties. + _supernode = newSupernode; + supernodeDidChange = YES; + } + } + + if (supernodeDidChange) { + ASHierarchyState stateToEnterOrExit = (newSupernode ? newSupernode.hierarchyState + : oldSupernode.hierarchyState); + + BOOL parentWasOrIsRasterized = (newSupernode ? newSupernode.shouldRasterizeDescendants + : oldSupernode.shouldRasterizeDescendants); + if (parentWasOrIsRasterized) { + stateToEnterOrExit |= ASHierarchyStateRasterized; + } + if (newSupernode) { + [self enterHierarchyState:stateToEnterOrExit]; } else { - [self exitHierarchyState:oldHierarchyState]; + [self exitHierarchyState:stateToEnterOrExit]; } } } diff --git a/AsyncDisplayKit/Private/ASDisplayNode+AsyncDisplay.mm b/AsyncDisplayKit/Private/ASDisplayNode+AsyncDisplay.mm index bdfb9b2729..4242881a5b 100644 --- a/AsyncDisplayKit/Private/ASDisplayNode+AsyncDisplay.mm +++ b/AsyncDisplayKit/Private/ASDisplayNode+AsyncDisplay.mm @@ -87,7 +87,7 @@ static void __ASDisplayLayerDecrementConcurrentDisplayCount(BOOL displayIsAsync, BOOL rasterizingFromAscendent = (_hierarchyState & ASHierarchyStateRasterized); - // if super node is rasterizing descendents, subnodes will not have had layout calls becase they don't have layers + // if super node is rasterizing descendents, subnodes will not have had layout calls because they don't have layers if (rasterizingFromAscendent) { [self __layout]; } diff --git a/AsyncDisplayKitTests/ASDisplayNodeTests.m b/AsyncDisplayKitTests/ASDisplayNodeTests.m index ae37bc8765..c49f56a660 100644 --- a/AsyncDisplayKitTests/ASDisplayNodeTests.m +++ b/AsyncDisplayKitTests/ASDisplayNodeTests.m @@ -1719,7 +1719,7 @@ static inline BOOL _CGPointEqualToPointWithEpsilon(CGPoint point1, CGPoint point ASTestWindow *window = [ASTestWindow new]; [window addSubview:cellNode.view]; XCTAssert(node.hasFetchedData); - XCTAssert(node.interfaceState == ASInterfaceStateFetchData); + XCTAssert(node.interfaceState == ASInterfaceStateInHierarchy); } - (void)testInitWithViewClass diff --git a/AsyncDisplayKitTests/ASSnapshotTestCase.mm b/AsyncDisplayKitTests/ASSnapshotTestCase.mm index a70b21a3d2..32c96590d6 100644 --- a/AsyncDisplayKitTests/ASSnapshotTestCase.mm +++ b/AsyncDisplayKitTests/ASSnapshotTestCase.mm @@ -7,6 +7,7 @@ */ #import "ASSnapshotTestCase.h" +#import "ASDisplayNode+FrameworkPrivate.h" #import "ASDisplayNodeInternal.h" @implementation ASSnapshotTestCase @@ -46,6 +47,7 @@ + (void)hackilySynchronouslyRecursivelyRenderNode:(ASDisplayNode *)node { +// TODO: Reconfigure this to be able to use [node recursivelyEnsureDisplay]; [self _recursivelySetDisplaysAsynchronously:NO forNode:node]; [self _recursivelyLayoutAndDisplayNode:node]; }