[ASDisplayNode] Improve locking in ASDisplayNode (#3172)

* Improve locking in ASDisplayNode

* Address first bunch of comments

* Changed `view` and `layer` methods for locking

* Adress comments
This commit is contained in:
Michael Schneider
2017-03-14 07:27:34 -07:00
committed by GitHub
parent b1cfd76cee
commit e6ee24debc
5 changed files with 310 additions and 239 deletions

View File

@@ -118,12 +118,12 @@
_viewControllerNode.frame = self.bounds; _viewControllerNode.frame = self.bounds;
} }
- (void)_locked_rootNodeDidInvalidateSize - (void)_rootNodeDidInvalidateSize
{ {
if (_interactionDelegate != nil) { if (_interactionDelegate != nil) {
[_interactionDelegate nodeDidInvalidateSize:self]; [_interactionDelegate nodeDidInvalidateSize:self];
} else { } else {
[super _locked_rootNodeDidInvalidateSize]; [super _rootNodeDidInvalidateSize];
} }
} }

File diff suppressed because it is too large Load Diff

View File

@@ -34,11 +34,15 @@
- (NSObject *)drawParameters - (NSObject *)drawParameters
{ {
if (_flags.implementsDrawParameters) { __instanceLock__.lock();
return [self drawParametersForAsyncLayer:self.asyncLayer]; BOOL implementsDrawParameters = _flags.implementsDrawParameters;
} __instanceLock__.unlock();
return nil; if (implementsDrawParameters) {
return [self drawParametersForAsyncLayer:self.asyncLayer];
} else {
return nil;
}
} }
- (void)_recursivelyRasterizeSelfAndSublayersWithIsCancelledBlock:(asdisplaynode_iscancelled_block_t)isCancelledBlock displayBlocks:(NSMutableArray *)displayBlocks - (void)_recursivelyRasterizeSelfAndSublayersWithIsCancelledBlock:(asdisplaynode_iscancelled_block_t)isCancelledBlock displayBlocks:(NSMutableArray *)displayBlocks
@@ -47,8 +51,10 @@
if (self.isHidden || self.alpha <= 0.0) { if (self.isHidden || self.alpha <= 0.0) {
return; return;
} }
__instanceLock__.lock();
BOOL rasterizingFromAscendent = (_hierarchyState & ASHierarchyStateRasterized); BOOL rasterizingFromAscendent = (_hierarchyState & ASHierarchyStateRasterized);
__instanceLock__.unlock();
// if super node is rasterizing descendants, subnodes will not have had layout calls because they don't have layers // if super node is rasterizing descendants, subnodes will not have had layout calls because they don't have layers
if (rasterizingFromAscendent) { if (rasterizingFromAscendent) {
@@ -170,11 +176,11 @@
BOOL opaque = self.opaque; BOOL opaque = self.opaque;
CGRect bounds = self.bounds; CGRect bounds = self.bounds;
CGFloat contentsScaleForDisplay = _contentsScaleForDisplay; CGFloat contentsScaleForDisplay = _contentsScaleForDisplay;
__instanceLock__.unlock();
// Capture drawParameters from delegate on main thread, if this node is displaying itself rather than recursively rasterizing. // Capture drawParameters from delegate on main thread, if this node is displaying itself rather than recursively rasterizing.
id drawParameters = (shouldBeginRasterizing == NO ? [self drawParameters] : nil); id drawParameters = (shouldBeginRasterizing == NO ? [self drawParameters] : nil);
__instanceLock__.unlock();
// Only the -display methods should be called if we can't size the graphics buffer to use. // Only the -display methods should be called if we can't size the graphics buffer to use.
if (CGRectIsEmpty(bounds) && (shouldBeginRasterizing || shouldCreateGraphicsContext)) { if (CGRectIsEmpty(bounds) && (shouldBeginRasterizing || shouldCreateGraphicsContext)) {
@@ -224,11 +230,21 @@
CGContextRef currentContext = UIGraphicsGetCurrentContext(); CGContextRef currentContext = UIGraphicsGetCurrentContext();
UIImage *image = nil; UIImage *image = nil;
ASDisplayNodeContextModifier willDisplayNodeContentWithRenderingContext = nil;
ASDisplayNodeContextModifier didDisplayNodeContentWithRenderingContext = nil;
if (currentContext) {
__instanceLock__.lock();
willDisplayNodeContentWithRenderingContext = _willDisplayNodeContentWithRenderingContext;
didDisplayNodeContentWithRenderingContext = _didDisplayNodeContentWithRenderingContext;
__instanceLock__.unlock();
}
// For -display methods, we don't have a context, and thus will not call the _willDisplayNodeContentWithRenderingContext or // For -display methods, we don't have a context, and thus will not call the _willDisplayNodeContentWithRenderingContext or
// _didDisplayNodeContentWithRenderingContext blocks. It's up to the implementation of -display... to do what it needs. // _didDisplayNodeContentWithRenderingContext blocks. It's up to the implementation of -display... to do what it needs.
if (currentContext && _willDisplayNodeContentWithRenderingContext) { if (willDisplayNodeContentWithRenderingContext != nil) {
_willDisplayNodeContentWithRenderingContext(currentContext); willDisplayNodeContentWithRenderingContext(currentContext);
} }
// Decide if we use a class or instance method to draw or display. // Decide if we use a class or instance method to draw or display.
@@ -242,8 +258,8 @@
isCancelled:isCancelledBlock isRasterizing:rasterizing]; isCancelled:isCancelledBlock isRasterizing:rasterizing];
} }
if (currentContext && _didDisplayNodeContentWithRenderingContext) { if (didDisplayNodeContentWithRenderingContext != nil) {
_didDisplayNodeContentWithRenderingContext(currentContext); didDisplayNodeContentWithRenderingContext(currentContext);
} }
if (shouldCreateGraphicsContext) { if (shouldCreateGraphicsContext) {
@@ -263,12 +279,17 @@
- (void)displayAsyncLayer:(_ASDisplayLayer *)asyncLayer asynchronously:(BOOL)asynchronously - (void)displayAsyncLayer:(_ASDisplayLayer *)asyncLayer asynchronously:(BOOL)asynchronously
{ {
ASDisplayNodeAssertMainThread(); ASDisplayNodeAssertMainThread();
ASDN::MutexLocker l(__instanceLock__); __instanceLock__.lock();
if (_hierarchyState & ASHierarchyStateRasterized) { if (_hierarchyState & ASHierarchyStateRasterized) {
__instanceLock__.unlock();
return; return;
} }
CALayer *layer = _layer;
__instanceLock__.unlock();
// for async display, capture the current displaySentinel value to bail early when the job is executed if another is // for async display, capture the current displaySentinel value to bail early when the job is executed if another is
// enqueued // enqueued
@@ -306,10 +327,10 @@
UIImage *image = (UIImage *)value; UIImage *image = (UIImage *)value;
BOOL stretchable = (NO == UIEdgeInsetsEqualToEdgeInsets(image.capInsets, UIEdgeInsetsZero)); BOOL stretchable = (NO == UIEdgeInsetsEqualToEdgeInsets(image.capInsets, UIEdgeInsetsZero));
if (stretchable) { if (stretchable) {
ASDisplayNodeSetupLayerContentsWithResizableImage(_layer, image); ASDisplayNodeSetupLayerContentsWithResizableImage(layer, image);
} else { } else {
_layer.contentsScale = self.contentsScale; layer.contentsScale = self.contentsScale;
_layer.contents = (id)image.CGImage; layer.contents = (id)image.CGImage;
} }
[self didDisplayAsyncLayer:self.asyncLayer]; [self didDisplayAsyncLayer:self.asyncLayer];
} }
@@ -323,7 +344,7 @@
// while synchronizing the final application of the results to the layer's contents property (completionBlock). // while synchronizing the final application of the results to the layer's contents property (completionBlock).
// First, look to see if we are expected to join a parent's transaction container. // First, look to see if we are expected to join a parent's transaction container.
CALayer *containerLayer = _layer.asyncdisplaykit_parentTransactionContainer ? : _layer; CALayer *containerLayer = layer.asyncdisplaykit_parentTransactionContainer ? : layer;
// In the case that a transaction does not yet exist (such as for an individual node outside of a container), // In the case that a transaction does not yet exist (such as for an individual node outside of a container),
// this call will allocate the transaction and add it to _ASAsyncTransactionGroup. // this call will allocate the transaction and add it to _ASAsyncTransactionGroup.

View File

@@ -218,7 +218,7 @@ __unused static NSString * _Nonnull NSStringFromASHierarchyState(ASHierarchyStat
* @abstract Subclass hook for nodes that are acting as root nodes. This method is called if one of the subnodes * @abstract Subclass hook for nodes that are acting as root nodes. This method is called if one of the subnodes
* size is invalidated and may need to result in a different size as the current calculated size. * size is invalidated and may need to result in a different size as the current calculated size.
*/ */
- (void)_locked_rootNodeDidInvalidateSize; - (void)_rootNodeDidInvalidateSize;
/** /**
* @abstract Subclass hook for nodes that are acting as root nodes. This method is called after measurement * @abstract Subclass hook for nodes that are acting as root nodes. This method is called after measurement

View File

@@ -200,9 +200,6 @@ FOUNDATION_EXPORT NSString * const ASRenderingEngineDidDisplayNodesScheduledBefo
/// Bitmask to check which methods an object overrides. /// Bitmask to check which methods an object overrides.
@property (nonatomic, assign, readonly) ASDisplayNodeMethodOverrides methodOverrides; @property (nonatomic, assign, readonly) ASDisplayNodeMethodOverrides methodOverrides;
// Swizzle to extend the builtin functionality with custom logic
- (BOOL)__shouldLoadViewOrLayer;
/** /**
* Invoked before a call to setNeedsLayout to the underlying view * Invoked before a call to setNeedsLayout to the underlying view
*/ */
@@ -218,11 +215,6 @@ FOUNDATION_EXPORT NSString * const ASRenderingEngineDidDisplayNodesScheduledBefo
*/ */
- (void)__layout; - (void)__layout;
/*
* Internal method to set the supernode
*/
- (void)__setSupernode:(nullable ASDisplayNode *)supernode;
/** /**
* Internal method to add / replace / insert subnode and remove from supernode without checking if * Internal method to add / replace / insert subnode and remove from supernode without checking if
* node has automaticallyManagesSubnodes set to YES. * node has automaticallyManagesSubnodes set to YES.
@@ -241,7 +233,7 @@ FOUNDATION_EXPORT NSString * const ASRenderingEngineDidDisplayNodesScheduledBefo
- (void)__decrementVisibilityNotificationsDisabled; - (void)__decrementVisibilityNotificationsDisabled;
/// Helper method to summarize whether or not the node run through the display process /// Helper method to summarize whether or not the node run through the display process
- (BOOL)__implementsDisplay; - (BOOL)_implementsDisplay;
/// Display the node's view/layer immediately on the current thread, bypassing the background thread rendering. Will be deprecated. /// Display the node's view/layer immediately on the current thread, bypassing the background thread rendering. Will be deprecated.
- (void)displayImmediately; - (void)displayImmediately;