From dc6d2e76604083ca8a73160e91c562a53410af89 Mon Sep 17 00:00:00 2001 From: Michael Schneider Date: Wed, 4 May 2016 11:52:45 -0700 Subject: [PATCH] Improve Transition ID handling --- AsyncDisplayKit/ASDisplayNode.mm | 89 +++++++++++-------- .../Private/ASDisplayNodeInternal.h | 2 + 2 files changed, 54 insertions(+), 37 deletions(-) diff --git a/AsyncDisplayKit/ASDisplayNode.mm b/AsyncDisplayKit/ASDisplayNode.mm index 9e159498b2..6d8515d74f 100644 --- a/AsyncDisplayKit/ASDisplayNode.mm +++ b/AsyncDisplayKit/ASDisplayNode.mm @@ -654,6 +654,8 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c) return (!_flags.isMeasured || !ASSizeRangeEqualToSizeRange(constrainedSize, _constrainedSize)); } +#pragma mark - Layout Transition + - (void)transitionLayoutWithAnimation:(BOOL)animated shouldMeasureAsync:(BOOL)shouldMeasureAsync measurementCompletion:(void(^)())completion @@ -681,10 +683,10 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c) ASDisplayNodeAssert(ASHierarchyStateIncludesLayoutPending(_hierarchyState) == NO, @"Can't start a transition when one of the supernodes is performing one."); } - int32_t transitionID = [self _newTransitionID]; + int32_t transitionID = [self _startNewTransition]; ASDisplayNodePerformBlockOnEverySubnode(self, ^(ASDisplayNode * _Nonnull node) { - ASDisplayNodeAssert([node _hasTransitionsInProgress] == NO, @"Can't start a transition when one of the subnodes is performing one."); + ASDisplayNodeAssert([node _hasTransitionInProgress] == NO, @"Can't start a transition when one of the subnodes is performing one."); node.hierarchyState |= ASHierarchyStateLayoutPending; node.pendingTransitionID = transitionID; }); @@ -726,13 +728,13 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c) ASSizeRange previousConstrainedSize = _constrainedSize; [self applyLayout:newLayout constrainedSize:constrainedSize layoutContext:nil]; - [self _invalidateTransitionSentinel]; - ASDisplayNodePerformBlockOnEverySubnode(self, ^(ASDisplayNode * _Nonnull node) { [node applyPendingLayoutContext]; [node _completeLayoutCalculation]; node.hierarchyState &= (~ASHierarchyStateLayoutPending); }); + + [self _finishOrCancelTransition]; if (completion) { completion(); @@ -781,7 +783,6 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c) } } - - (void)calculatedLayoutDidChange { // subclass override @@ -790,9 +791,10 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c) - (void)cancelLayoutTransitionsInProgress { ASDN::MutexLocker l(_propertyLock); - if ([self _hasTransitionsInProgress]) { - // Invalidate transition sentinel to cancel transitions in progress - [self _invalidateTransitionSentinel]; + if ([self _hasTransitionInProgress]) { + // Cancel transition in progress + [self _finishOrCancelTransition]; + // Tell subnodes to exit layout pending state and clear related properties ASDisplayNodePerformBlockOnEverySubnode(self, ^(ASDisplayNode * _Nonnull node) { node.hierarchyState &= (~ASHierarchyStateLayoutPending); @@ -800,8 +802,6 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c) } } -#pragma mark - Layout Transition - - (BOOL)usesImplicitHierarchyManagement { ASDN::MutexLocker l(_propertyLock); @@ -814,6 +814,40 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c) _usesImplicitHierarchyManagement = value; } +- (BOOL)_hasTransitionInProgress +{ + ASDN::MutexLocker l(_propertyLock); + return _transitionInProgress; +} + +/// Starts a new transition and returns the transition id +- (int32_t)_startNewTransition +{ + ASDN::MutexLocker l(_propertyLock); + _transitionInProgress = YES; + + if (!_transitionSentinel) { + _transitionSentinel = [[ASSentinel alloc] init]; + } + return [_transitionSentinel increment]; +} + +- (void)_finishOrCancelTransition +{ + ASDN::MutexLocker l(_propertyLock); + _transitionInProgress = NO; +} + +- (BOOL)_shouldAbortTransitionWithID:(int32_t)transitionID +{ + ASDN::MutexLocker l(_propertyLock); + if (_transitionInProgress) { + return _transitionSentinel == nil || transitionID != _transitionSentinel.value; + } + + return YES; +} + - (void)animateLayoutTransition:(id)context { [self __layoutSublayouts]; @@ -827,6 +861,7 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c) _pendingLayoutContext = nil; } + #pragma mark - _ASTransitionContextCompletionDelegate - (void)transitionContext:(_ASTransitionContext *)context didComplete:(BOOL)didComplete @@ -1689,9 +1724,11 @@ static NSInteger incrementIfFound(NSInteger i) { } if (supernodeDidChange) { + // Hierarchy state ASHierarchyState stateToEnterOrExit = (newSupernode ? newSupernode.hierarchyState : oldSupernode.hierarchyState); + // Rasterized state BOOL parentWasOrIsRasterized = (newSupernode ? newSupernode.shouldRasterizeDescendants : oldSupernode.shouldRasterizeDescendants); if (parentWasOrIsRasterized) { @@ -1700,6 +1737,10 @@ static NSInteger incrementIfFound(NSInteger i) { if (newSupernode) { [self enterHierarchyState:stateToEnterOrExit]; } else { + // If a node will be removed from the supernode it should go out from the layout pending state to remove all + // layout pending state related properties on the node + stateToEnterOrExit |= ASHierarchyStateLayoutPending; + [self exitHierarchyState:stateToEnterOrExit]; } } @@ -2644,38 +2685,12 @@ static const char *ASDisplayNodeDrawingPriorityKey = "ASDrawingPriority"; _flags.isInHierarchy = inHierarchy; } -- (BOOL)_hasTransitionsInProgress -{ - ASDN::MutexLocker l(_propertyLock); - return _transitionSentinel != nil; -} - -- (void)_invalidateTransitionSentinel -{ - ASDN::MutexLocker l(_propertyLock); - _transitionSentinel = nil; -} - -- (BOOL)_shouldAbortTransitionWithID:(int32_t)transitionID -{ - ASDN::MutexLocker l(_propertyLock); - return _transitionSentinel == nil || transitionID != _transitionSentinel.value; -} - -- (int32_t)_newTransitionID -{ - ASDN::MutexLocker l(_propertyLock); - if (!_transitionSentinel) { - _transitionSentinel = [[ASSentinel alloc] init]; - } - return [_transitionSentinel increment]; -} - - (id)finalLayoutable { return self; } + #pragma mark - ASEnvironment - (ASEnvironmentState)environmentState diff --git a/AsyncDisplayKit/Private/ASDisplayNodeInternal.h b/AsyncDisplayKit/Private/ASDisplayNodeInternal.h index 4828b8bec6..b4668ac613 100644 --- a/AsyncDisplayKit/Private/ASDisplayNodeInternal.h +++ b/AsyncDisplayKit/Private/ASDisplayNodeInternal.h @@ -93,7 +93,9 @@ FOUNDATION_EXPORT NSString * const ASRenderingEngineDidDisplayNodesScheduledBefo ASDisplayNode * __weak _supernode; ASSentinel *_displaySentinel; + ASSentinel *_transitionSentinel; + BOOL _transitionInProgress; // This is the desired contentsScale, not the scale at which the layer's contents should be displayed CGFloat _contentsScaleForDisplay;