diff --git a/Source/ASDisplayNode.h b/Source/ASDisplayNode.h index 6c2299da8..4c75d2336 100644 --- a/Source/ASDisplayNode.h +++ b/Source/ASDisplayNode.h @@ -217,8 +217,7 @@ extern NSInteger const ASDefaultDrawingPriority; * * @return NO if the node wraps a _ASDisplayView, YES otherwise. */ -@property (nonatomic, readonly, assign, getter=isSynchronous) BOOL synchronous; - +@property (atomic, readonly, assign, getter=isSynchronous) BOOL synchronous; /** @name Getting view and layer */ diff --git a/Source/ASDisplayNode.mm b/Source/ASDisplayNode.mm index ef5fa5ffe..09dd27370 100644 --- a/Source/ASDisplayNode.mm +++ b/Source/ASDisplayNode.mm @@ -100,9 +100,9 @@ BOOL ASDisplayNodeSubclassOverridesSelector(Class subclass, SEL selector) // For classes like ASTableNode, ASCollectionNode, ASScrollNode and similar - we have to be sure to set certain properties // like setFrame: and setBackgroundColor: directly to the UIView and not apply it to the layer only. -BOOL ASDisplayNodeNeedsSpecialPropertiesHandlingForFlags(ASDisplayNodeFlags flags) +BOOL ASDisplayNodeNeedsSpecialPropertiesHandling(BOOL isSynchronous, BOOL isLayerBacked) { - return flags.synchronous && !flags.layerBacked; + return isSynchronous && !isLayerBacked; } _ASPendingState *ASDisplayNodeGetPendingState(ASDisplayNode *node) @@ -314,7 +314,7 @@ - (instancetype)initWithViewClass:(Class)viewClass ASDisplayNodeAssert([viewClass isSubclassOfClass:[UIView class]], @"should initialize with a subclass of UIView"); _viewClass = viewClass; - _flags.synchronous = ![viewClass isSubclassOfClass:[_ASDisplayView class]]; + self.synchronous = ![viewClass isSubclassOfClass:[_ASDisplayView class]]; return self; } @@ -328,7 +328,7 @@ - (instancetype)initWithLayerClass:(Class)layerClass ASDisplayNodeAssert([layerClass isSubclassOfClass:[CALayer class]], @"should initialize with a subclass of CALayer"); _layerClass = layerClass; - _flags.synchronous = ![layerClass isSubclassOfClass:[_ASDisplayLayer class]]; + self.synchronous = ![layerClass isSubclassOfClass:[_ASDisplayLayer class]]; _flags.layerBacked = YES; return self; @@ -378,7 +378,7 @@ - (void)setViewBlock:(ASDisplayNodeViewBlock)viewBlock ASDisplayNodeAssertNotNil(viewBlock, @"should initialize with a valid block that returns a UIView"); _viewBlock = viewBlock; - _flags.synchronous = YES; + self.synchronous = YES; } - (void)setLayerBlock:(ASDisplayNodeLayerBlock)layerBlock @@ -387,7 +387,7 @@ - (void)setLayerBlock:(ASDisplayNodeLayerBlock)layerBlock ASDisplayNodeAssertNotNil(layerBlock, @"should initialize with a valid block that returns a CALayer"); _layerBlock = layerBlock; - _flags.synchronous = YES; + self.synchronous = YES; _flags.layerBacked = YES; } @@ -411,7 +411,7 @@ - (void)dealloc _flags.isDeallocating = YES; // Synchronous nodes may not be able to call the hierarchy notifications, so only enforce for regular nodes. - ASDisplayNodeAssert(_flags.synchronous || !ASInterfaceStateIncludesVisible(_interfaceState), @"Node should always be marked invisible before deallocating. Node: %@", self); + ASDisplayNodeAssert(self.isSynchronous || !ASInterfaceStateIncludesVisible(_interfaceState), @"Node should always be marked invisible before deallocating. Node: %@", self); self.asyncLayer.asyncDelegate = nil; _view.asyncdisplaykit_node = nil; @@ -547,7 +547,7 @@ - (void)__unloadNode { ASDisplayNodeAssertMainThread(); ASDisplayNodeAssert([self isNodeLoaded], @"Implementation shouldn't call __unloadNode if not loaded: %@", self); - ASDisplayNodeAssert(_flags.synchronous == NO, @"Node created using -initWithViewBlock:/-initWithLayerBlock: cannot be unloaded. Node: %@", self); + ASDisplayNodeAssert(self.isSynchronous == NO, @"Node created using -initWithViewBlock:/-initWithLayerBlock: cannot be unloaded. Node: %@", self); ASDN::MutexLocker l(__instanceLock__); if (_flags.layerBacked) { @@ -583,7 +583,7 @@ - (UIView *)_locked_viewToLoad } // Special handling of wrapping UIKit components - if (_flags.synchronous) { + if (self.isSynchronous) { // UIImageView layers. More details on the flags if ([_viewClass isSubclassOfClass:[UIImageView class]]) { _flags.canClearContentsOfLayer = NO; @@ -803,12 +803,6 @@ - (_ASDisplayLayer *)_locked_asyncLayer return [_layer isKindOfClass:[_ASDisplayLayer class]] ? (_ASDisplayLayer *)_layer : nil; } -- (BOOL)isSynchronous -{ - ASDN::MutexLocker l(__instanceLock__); - return _flags.synchronous; -} - - (void)setLayerBacked:(BOOL)isLayerBacked { // Only call this if assertions are enabled – it could be expensive. @@ -836,7 +830,7 @@ - (BOOL)isLayerBacked - (BOOL)supportsLayerBacking { ASDN::MutexLocker l(__instanceLock__); - return !_flags.synchronous && !_flags.viewEverHadAGestureRecognizerAttached && _viewClass == [_ASDisplayView class] && _layerClass == [_ASDisplayLayer class]; + return !self.isSynchronous && !_flags.viewEverHadAGestureRecognizerAttached && _viewClass == [_ASDisplayView class] && _layerClass == [_ASDisplayLayer class]; } - (BOOL)shouldAnimateSizeChanges @@ -1948,7 +1942,7 @@ - (BOOL)displaysAsynchronously */ - (BOOL)_locked_displaysAsynchronously { - return _flags.synchronous == NO && _flags.displaysAsynchronously; + return self.isSynchronous == NO && _flags.displaysAsynchronously; } - (void)setDisplaysAsynchronously:(BOOL)displaysAsynchronously @@ -1958,7 +1952,7 @@ - (void)setDisplaysAsynchronously:(BOOL)displaysAsynchronously ASDN::MutexLocker l(__instanceLock__); // Can't do this for synchronous nodes (using layers that are not _ASDisplayLayer and so we can't control display prevention/cancel) - if (_flags.synchronous) { + if (self.isSynchronous) { return; } @@ -2052,7 +2046,7 @@ - (void)setContentsScaleForDisplay:(CGFloat)contentsScaleForDisplay - (void)displayImmediately { ASDisplayNodeAssertMainThread(); - ASDisplayNodeAssert(!_flags.synchronous, @"this method is designed for asynchronous mode only"); + ASDisplayNodeAssert(!self.isSynchronous, @"this method is designed for asynchronous mode only"); [self.asyncLayer displayImmediately]; } @@ -2073,7 +2067,7 @@ - (void)__setNeedsDisplay BOOL nowDisplay = ASInterfaceStateIncludesDisplay(_interfaceState); // FIXME: This should not need to recursively display, so create a non-recursive variant. // The semantics of setNeedsDisplay (as defined by CALayer behavior) are not recursive. - if (_layer != nil && !_flags.synchronous && nowDisplay && [self _implementsDisplay]) { + if (_layer != nil && !self.isSynchronous && nowDisplay && [self _implementsDisplay]) { shouldScheduleForDisplay = YES; } } @@ -2317,7 +2311,7 @@ - (void)setDisplaySuspended:(BOOL)flag __instanceLock__.lock(); // Can't do this for synchronous nodes (using layers that are not _ASDisplayLayer and so we can't control display prevention/cancel) - if (_flags.synchronous || _flags.displaySuspended == flag) { + if (self.isSynchronous || _flags.displaySuspended == flag) { __instanceLock__.unlock(); return; } @@ -3406,7 +3400,7 @@ - (void)setHierarchyState:(ASHierarchyState)newState // Entered rasterization state. if (newState & ASHierarchyStateRasterized) { - ASDisplayNodeAssert(_flags.synchronous == NO, @"Node created using -initWithViewBlock:/-initWithLayerBlock: cannot be added to subtree of node with shouldRasterizeDescendants=YES. Node: %@", self); + ASDisplayNodeAssert(self.isSynchronous == NO, @"Node created using -initWithViewBlock:/-initWithLayerBlock: cannot be added to subtree of node with shouldRasterizeDescendants=YES. Node: %@", self); } // Entered or exited range managed state. @@ -3907,7 +3901,7 @@ - (void)_locked_applyPendingViewState if (_flags.layerBacked) { [_pendingViewState applyToLayer:self.layer]; } else { - BOOL specialPropertiesHandling = ASDisplayNodeNeedsSpecialPropertiesHandlingForFlags(_flags); + BOOL specialPropertiesHandling = ASDisplayNodeNeedsSpecialPropertiesHandling(self.isSynchronous, _flags.layerBacked); [_pendingViewState applyToView:self.view withSpecialPropertiesHandling:specialPropertiesHandling]; } diff --git a/Source/Private/ASDisplayNode+UIViewBridge.mm b/Source/Private/ASDisplayNode+UIViewBridge.mm index 73322a343..2568fdd8b 100644 --- a/Source/Private/ASDisplayNode+UIViewBridge.mm +++ b/Source/Private/ASDisplayNode+UIViewBridge.mm @@ -241,7 +241,7 @@ - (void)setFrame:(CGRect)rect // For classes like ASTableNode, ASCollectionNode, ASScrollNode and similar - make sure UIView gets setFrame: struct ASDisplayNodeFlags flags = _flags; - BOOL specialPropertiesHandling = ASDisplayNodeNeedsSpecialPropertiesHandlingForFlags(flags); + BOOL specialPropertiesHandling = ASDisplayNodeNeedsSpecialPropertiesHandling(self.isSynchronous, flags.layerBacked); BOOL nodeLoaded = __loaded(self); BOOL isMainThread = ASDisplayNodeThreadIsMain(); @@ -635,7 +635,7 @@ - (void)setBackgroundColor:(UIColor *)newBackgroundColor if (shouldApply) { CGColorRef oldBackgroundCGColor = _layer.backgroundColor; - BOOL specialPropertiesHandling = ASDisplayNodeNeedsSpecialPropertiesHandlingForFlags(_flags); + BOOL specialPropertiesHandling = ASDisplayNodeNeedsSpecialPropertiesHandling(self.isSynchronous, _flags.layerBacked); if (specialPropertiesHandling) { _view.backgroundColor = newBackgroundColor; } else { diff --git a/Source/Private/ASDisplayNodeInternal.h b/Source/Private/ASDisplayNodeInternal.h index ed973e647..a815142ac 100644 --- a/Source/Private/ASDisplayNodeInternal.h +++ b/Source/Private/ASDisplayNodeInternal.h @@ -38,7 +38,7 @@ NS_ASSUME_NONNULL_BEGIN struct ASDisplayNodeFlags; BOOL ASDisplayNodeSubclassOverridesSelector(Class subclass, SEL selector); -BOOL ASDisplayNodeNeedsSpecialPropertiesHandlingForFlags(ASDisplayNodeFlags flags); +BOOL ASDisplayNodeNeedsSpecialPropertiesHandling(BOOL isSynchronous, BOOL isLayerBacked); /// Get the pending view state for the node, creating one if needed. _ASPendingState * ASDisplayNodeGetPendingState(ASDisplayNode * node); @@ -73,7 +73,6 @@ FOUNDATION_EXPORT NSString * const ASRenderingEngineDidDisplayNodesScheduledBefo struct ASDisplayNodeFlags { // public properties - unsigned synchronous:1; unsigned viewEverHadAGestureRecognizerAttached:1; unsigned layerBacked:1; unsigned displaysAsynchronously:1; @@ -208,6 +207,9 @@ FOUNDATION_EXPORT NSString * const ASRenderingEngineDidDisplayNodesScheduledBefo /// Bitmask to check which methods an object overrides. @property (nonatomic, assign, readonly) ASDisplayNodeMethodOverrides methodOverrides; +/// Atomic BOOL that indicates whether the node wraps a synchronous layer or view class. +@property (atomic, assign, readwrite, getter=isSynchronous) BOOL synchronous; + /** * Invoked before a call to setNeedsLayout to the underlying view */