diff --git a/AsyncDisplayKit/ASDisplayNode.mm b/AsyncDisplayKit/ASDisplayNode.mm index 8b5dd63366..7cafc438d5 100644 --- a/AsyncDisplayKit/ASDisplayNode.mm +++ b/AsyncDisplayKit/ASDisplayNode.mm @@ -61,6 +61,7 @@ NSString * const ASRenderingEngineDidDisplayNodesScheduledBeforeTimestamp = @"AS @synthesize name = _name; @synthesize preferredFrameSize = _preferredFrameSize; @synthesize isFinalLayoutable = _isFinalLayoutable; +@synthesize threadSafeBounds = _threadSafeBounds; static BOOL usesImplicitHierarchyManagement = FALSE; @@ -428,11 +429,13 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c) ASDisplayNodeAssert(![view isKindOfClass:[_ASDisplayView class]], @"View block should return a synchronously displayed view"); _viewBlock = nil; _viewClass = [view class]; + _usesDisplayView = [_viewClass isKindOfClass:[_ASDisplayView class]]; } else { if (!_viewClass) { _viewClass = [self.class viewClass]; } view = [[_viewClass alloc] init]; + _usesDisplayView = [_viewClass isKindOfClass:[_ASDisplayView class]]; } return view; @@ -1918,6 +1921,18 @@ void recursivelyTriggerDisplayForLayer(CALayer *layer, BOOL shouldBlock) return _preferredFrameSize; } +- (CGRect)threadSafeBounds +{ + ASDN::MutexLocker l(_propertyLock); + return _threadSafeBounds; +} + +- (void)setThreadSafeBounds:(CGRect)newBounds +{ + ASDN::MutexLocker l(_propertyLock); + _threadSafeBounds = newBounds; +} + - (UIImage *)placeholderImage { return nil; diff --git a/AsyncDisplayKit/ASTextNode.mm b/AsyncDisplayKit/ASTextNode.mm index ff41c90d05..f51f59f0f1 100644 --- a/AsyncDisplayKit/ASTextNode.mm +++ b/AsyncDisplayKit/ASTextNode.mm @@ -218,10 +218,9 @@ static NSArray *DefaultLinkAttributeNames = @[ NSLinkAttributeName ]; #pragma mark - Renderer Management -//only safe to call on the main thread because self.bounds is only safe to call on the main thread one our node is loaded - (ASTextKitRenderer *)_renderer { - return [self _rendererWithBounds:self.bounds]; + return [self _rendererWithBounds:self.threadSafeBounds]; } - (ASTextKitRenderer *)_rendererWithBounds:(CGRect)bounds @@ -268,7 +267,7 @@ static NSArray *DefaultLinkAttributeNames = @[ NSLinkAttributeName ]; - (void)_invalidateRendererIfNeeded { - [self _invalidateRendererIfNeededForBoundsSize:self.bounds.size]; + [self _invalidateRendererIfNeededForBoundsSize:self.threadSafeBounds.size]; } - (void)_invalidateRendererIfNeededForBoundsSize:(CGSize)boundsSize @@ -438,7 +437,7 @@ static NSArray *DefaultLinkAttributeNames = @[ NSLinkAttributeName ]; - (NSObject *)drawParametersForAsyncLayer:(_ASDisplayLayer *)layer { - return [[ASTextNodeDrawParameters alloc] initWithBounds:self.bounds backgroundColor:self.backgroundColor]; + return [[ASTextNodeDrawParameters alloc] initWithBounds:self.threadSafeBounds backgroundColor:self.backgroundColor]; } #pragma mark - Attributes @@ -990,7 +989,6 @@ static NSArray *DefaultLinkAttributeNames = @[ NSLinkAttributeName ]; } } -//only safe to call on main thread, because [self _renderer] is only safe to call on the main thread - (UIEdgeInsets)shadowPadding { return [self shadowPaddingWithRenderer:[self _renderer]]; diff --git a/AsyncDisplayKit/Details/_ASDisplayView.mm b/AsyncDisplayKit/Details/_ASDisplayView.mm index 25f92dc332..1c117928e2 100644 --- a/AsyncDisplayKit/Details/_ASDisplayView.mm +++ b/AsyncDisplayKit/Details/_ASDisplayView.mm @@ -201,6 +201,12 @@ self.layer.contentsGravity = (contentMode != UIViewContentModeRedraw) ? ASDisplayNodeCAContentsGravityFromUIContentMode(contentMode) : kCAGravityResize; } +- (void)setBounds:(CGRect)bounds +{ + [super setBounds:bounds]; + _node.threadSafeBounds = bounds; +} + #pragma mark - Event Handling + UIResponder Overrides - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { diff --git a/AsyncDisplayKit/Private/ASDisplayNode+UIViewBridge.mm b/AsyncDisplayKit/Private/ASDisplayNode+UIViewBridge.mm index e947ea8ed5..aed7bfb495 100644 --- a/AsyncDisplayKit/Private/ASDisplayNode+UIViewBridge.mm +++ b/AsyncDisplayKit/Private/ASDisplayNode+UIViewBridge.mm @@ -211,6 +211,10 @@ if (shouldApply) { _layer.layerProperty = (layerValueExpr); } else { ASDisplayNo { _bridge_prologue_write; _setToViewOrLayer(bounds, newBounds, bounds, newBounds); + // If _ASDisplayView is available, it already sets the new bounds to threadSafeBounds. + if (! (__loaded(self) && _usesDisplayView)) { + self.threadSafeBounds = newBounds; + } } - (CGRect)frame diff --git a/AsyncDisplayKit/Private/ASDisplayNodeInternal.h b/AsyncDisplayKit/Private/ASDisplayNodeInternal.h index 8a3aa97b80..b10c6d7f8c 100644 --- a/AsyncDisplayKit/Private/ASDisplayNodeInternal.h +++ b/AsyncDisplayKit/Private/ASDisplayNodeInternal.h @@ -116,7 +116,8 @@ FOUNDATION_EXPORT NSString * const ASRenderingEngineDidDisplayNodesScheduledBefo ASDisplayNodeDidLoadBlock _nodeLoadedBlock; Class _viewClass; Class _layerClass; - + BOOL _usesDisplayView; + UIImage *_placeholderImage; CALayer *_placeholderLayer; @@ -145,6 +146,8 @@ FOUNDATION_EXPORT NSString * const ASRenderingEngineDidDisplayNodesScheduledBefo // Bitmask to check which methods an object overrides. @property (nonatomic, assign, readonly) ASDisplayNodeMethodOverrides methodOverrides; +@property (nonatomic, assign) CGRect threadSafeBounds; + // Swizzle to extend the builtin functionality with custom logic - (BOOL)__shouldLoadViewOrLayer;