Fix race in ASDisplayNodeRespectThreadAffinityOfNode

This commit is contained in:
Shannon Ma 2015-08-10 16:42:02 -07:00
parent 6275219f79
commit c26e9c7e94

View File

@ -71,12 +71,16 @@ void ASDisplayNodeRespectThreadAffinityOfNode(ASDisplayNode *node, void (^block)
return; return;
} }
if (node.nodeLoaded) { {
ASDisplayNodePerformBlockOnMainThread(^{ // Hold the lock to avoid a race where the node gets loaded while the block is in-flight.
ASDN::MutexLocker l(node->_propertyLock);
if (node.nodeLoaded) {
ASDisplayNodePerformBlockOnMainThread(^{
block();
});
} else {
block(); block();
}); }
} else {
block();
} }
} }
@ -121,12 +125,12 @@ void ASDisplayNodeRespectThreadAffinityOfNode(ASDisplayNode *node, void (^block)
- (void)_initializeInstance - (void)_initializeInstance
{ {
_contentsScaleForDisplay = ASScreenScale(); _contentsScaleForDisplay = ASScreenScale();
_displaySentinel = [[ASSentinel alloc] init]; _displaySentinel = [[ASSentinel alloc] init];
_flags.isInHierarchy = NO; _flags.isInHierarchy = NO;
_flags.displaysAsynchronously = YES; _flags.displaysAsynchronously = YES;
// As an optimization, it may be worth a caching system that performs these checks once per class in +initialize (see above). // As an optimization, it may be worth a caching system that performs these checks once per class in +initialize (see above).
_flags.implementsDrawRect = ([[self class] respondsToSelector:@selector(drawRect:withParameters:isCancelled:isRasterizing:)] ? 1 : 0); _flags.implementsDrawRect = ([[self class] respondsToSelector:@selector(drawRect:withParameters:isCancelled:isRasterizing:)] ? 1 : 0);
_flags.implementsImageDisplay = ([[self class] respondsToSelector:@selector(displayWithParameters:isCancelled:)] ? 1 : 0); _flags.implementsImageDisplay = ([[self class] respondsToSelector:@selector(displayWithParameters:isCancelled:)] ? 1 : 0);
@ -149,7 +153,7 @@ void ASDisplayNodeRespectThreadAffinityOfNode(ASDisplayNode *node, void (^block)
overrides |= ASDisplayNodeMethodOverrideCalculateSizeThatFits; overrides |= ASDisplayNodeMethodOverrideCalculateSizeThatFits;
} }
_methodOverrides = overrides; _methodOverrides = overrides;
_flexBasis = ASRelativeDimensionUnconstrained; _flexBasis = ASRelativeDimensionUnconstrained;
} }
@ -157,9 +161,9 @@ void ASDisplayNodeRespectThreadAffinityOfNode(ASDisplayNode *node, void (^block)
{ {
if (!(self = [super init])) if (!(self = [super init]))
return nil; return nil;
[self _initializeInstance]; [self _initializeInstance];
return self; return self;
} }
@ -169,7 +173,7 @@ void ASDisplayNodeRespectThreadAffinityOfNode(ASDisplayNode *node, void (^block)
return nil; return nil;
ASDisplayNodeAssert([viewClass isSubclassOfClass:[UIView class]], @"should initialize with a subclass of UIView"); ASDisplayNodeAssert([viewClass isSubclassOfClass:[UIView class]], @"should initialize with a subclass of UIView");
[self _initializeInstance]; [self _initializeInstance];
_viewClass = viewClass; _viewClass = viewClass;
_flags.synchronous = ![viewClass isSubclassOfClass:[_ASDisplayView class]]; _flags.synchronous = ![viewClass isSubclassOfClass:[_ASDisplayView class]];
@ -181,7 +185,7 @@ void ASDisplayNodeRespectThreadAffinityOfNode(ASDisplayNode *node, void (^block)
{ {
if (!(self = [super init])) if (!(self = [super init]))
return nil; return nil;
ASDisplayNodeAssert([layerClass isSubclassOfClass:[CALayer class]], @"should initialize with a subclass of CALayer"); ASDisplayNodeAssert([layerClass isSubclassOfClass:[CALayer class]], @"should initialize with a subclass of CALayer");
[self _initializeInstance]; [self _initializeInstance];
@ -500,7 +504,7 @@ void ASDisplayNodeRespectThreadAffinityOfNode(ASDisplayNode *node, void (^block)
} }
/** /**
* Core implementation of -displaysAsynchronously. * Core implementation of -displaysAsynchronously.
* Must be called with _propertyLock held. * Must be called with _propertyLock held.
*/ */
- (BOOL)_displaysAsynchronously - (BOOL)_displaysAsynchronously
@ -1142,7 +1146,7 @@ static NSInteger incrementIfFound(NSInteger i) {
[self willEnterHierarchy]; [self willEnterHierarchy];
} }
_flags.isEnteringHierarchy = NO; _flags.isEnteringHierarchy = NO;
CALayer *layer = self.layer; CALayer *layer = self.layer;
if (!self.layer.contents) { if (!self.layer.contents) {
[layer setNeedsDisplay]; [layer setNeedsDisplay];
@ -1426,11 +1430,11 @@ static NSInteger incrementIfFound(NSInteger i) {
- (void)layout - (void)layout
{ {
ASDisplayNodeAssertMainThread(); ASDisplayNodeAssertMainThread();
if (!_flags.isMeasured) { if (!_flags.isMeasured) {
return; return;
} }
// Assume that _layout was flattened and is 1-level deep. // Assume that _layout was flattened and is 1-level deep.
for (ASLayout *subnodeLayout in _layout.sublayouts) { for (ASLayout *subnodeLayout in _layout.sublayouts) {
ASDisplayNodeAssert([_subnodes containsObject:subnodeLayout.layoutableObject], @"Cached sublayouts must only contain subnodes' layout."); ASDisplayNodeAssert([_subnodes containsObject:subnodeLayout.layoutableObject], @"Cached sublayouts must only contain subnodes' layout.");