Clean up ASDisplayNode internal flags.

* Reorganise and rename `_flags` for clarity and consistency.
* Remove ambiguity between `implementsDisplay` and `hasClassDisplay`.
* Delete useless `hasWillDisplayAsyncLayer` check -- make it a simple
  subclass override point, as with `didDisplayAsyncLayer:`.
* Minor comment cleanup.
This commit is contained in:
Nadine Salter 2014-12-02 16:53:02 -08:00
parent a53bc08eaf
commit a30c087616
5 changed files with 87 additions and 83 deletions

View File

@ -74,7 +74,7 @@
/** /**
* @abstract Returns whether the view is synchronous. * @abstract Returns whether the node is synchronous.
* *
* @return NO if the node wraps a _ASDisplayView, YES otherwise. * @return NO if the node wraps a _ASDisplayView, YES otherwise.
*/ */
@ -98,7 +98,7 @@
/** /**
* @abstract Returns whether a node's backing view or layer is loaded. * @abstract Returns whether a node's backing view or layer is loaded.
* *
* @return YES if a view is loaded, or if isLayerBacked is YES and layer is not nil; NO otherwise. * @return YES if a view is loaded, or if layerBacked is YES and layer is not nil; NO otherwise.
*/ */
@property (atomic, readonly, assign, getter=isNodeLoaded) BOOL nodeLoaded; @property (atomic, readonly, assign, getter=isNodeLoaded) BOOL nodeLoaded;

View File

@ -103,22 +103,19 @@ void ASDisplayNodePerformBlockOnMainThread(void (^block)())
#pragma mark - Lifecycle #pragma mark - Lifecycle
// Avoid recursive loops if a subclass implements an init method that calls -initWith*Class:
- (void)_initializeInstance - (void)_initializeInstance
{ {
_contentsScaleForDisplay = ASDisplayNodeScreenScale(); _contentsScaleForDisplay = ASDisplayNodeScreenScale();
_displaySentinel = [[ASSentinel alloc] init]; _displaySentinel = [[ASSentinel alloc] init];
_flags.inWindow = NO; _flags.isInWindow = 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.implementsDisplay = [[self class] respondsToSelector:@selector(drawRect:withParameters:isCancelled:isRasterizing:)] || [self.class respondsToSelector:@selector(displayWithParameters:isCancelled:)]; _flags.implementsDrawRect = ([[self class] respondsToSelector:@selector(drawRect:withParameters:isCancelled:isRasterizing:)] ? 1 : 0);
_flags.implementsImageDisplay = ([[self class] respondsToSelector:@selector(displayWithParameters:isCancelled:)] ? 1 : 0);
_flags.hasClassDisplay = ([[self class] respondsToSelector:@selector(displayWithParameters:isCancelled:)] ? 1 : 0); _flags.implementsDrawParameters = ([self respondsToSelector:@selector(drawParametersForAsyncLayer:)] ? 1 : 0);
_flags.hasWillDisplayAsyncLayer = ([self respondsToSelector:@selector(willDisplayAsyncLayer:)] ? 1 : 0);
_flags.hasDrawParametersForAsyncLayer = ([self respondsToSelector:@selector(drawParametersForAsyncLayer:)] ? 1 : 0);
} }
- (id)init - (id)init
@ -140,7 +137,7 @@ void ASDisplayNodePerformBlockOnMainThread(void (^block)())
[self _initializeInstance]; [self _initializeInstance];
_viewClass = viewClass; _viewClass = viewClass;
_flags.isSynchronous = ![viewClass isSubclassOfClass:[_ASDisplayView class]]; _flags.synchronous = ![viewClass isSubclassOfClass:[_ASDisplayView class]];
return self; return self;
} }
@ -154,8 +151,8 @@ void ASDisplayNodePerformBlockOnMainThread(void (^block)())
[self _initializeInstance]; [self _initializeInstance];
_layerClass = layerClass; _layerClass = layerClass;
_flags.isSynchronous = ![layerClass isSubclassOfClass:[_ASDisplayLayer class]]; _flags.synchronous = ![layerClass isSubclassOfClass:[_ASDisplayLayer class]];
_flags.isLayerBacked = YES; _flags.layerBacked = YES;
return self; return self;
} }
@ -178,7 +175,7 @@ void ASDisplayNodePerformBlockOnMainThread(void (^block)())
_view = nil; _view = nil;
_subnodes = nil; _subnodes = nil;
if (_flags.isLayerBacked) if (_flags.layerBacked)
_layer.delegate = nil; _layer.delegate = nil;
_layer = nil; _layer = nil;
@ -277,8 +274,8 @@ void ASDisplayNodePerformBlockOnMainThread(void (^block)())
- (UIView *)view - (UIView *)view
{ {
ASDisplayNodeAssert(!_flags.isLayerBacked, @"Call to -view undefined on layer-backed nodes"); ASDisplayNodeAssert(!_flags.layerBacked, @"Call to -view undefined on layer-backed nodes");
if (_flags.isLayerBacked) { if (_flags.layerBacked) {
return nil; return nil;
} }
if (!_view) { if (!_view) {
@ -293,7 +290,7 @@ void ASDisplayNodePerformBlockOnMainThread(void (^block)())
if (!_layer) { if (!_layer) {
ASDisplayNodeAssertMainThread(); ASDisplayNodeAssertMainThread();
if (!_flags.isLayerBacked) { if (!_flags.layerBacked) {
return self.view.layer; return self.view.layer;
} }
[self _loadViewOrLayerIsLayerBacked:YES]; [self _loadViewOrLayerIsLayerBacked:YES];
@ -304,10 +301,10 @@ void ASDisplayNodePerformBlockOnMainThread(void (^block)())
// Returns nil if our view is not an _ASDisplayView, but will create it if necessary. // Returns nil if our view is not an _ASDisplayView, but will create it if necessary.
- (_ASDisplayView *)ensureAsyncView - (_ASDisplayView *)ensureAsyncView
{ {
return _flags.isSynchronous ? nil:(_ASDisplayView *)self.view; return _flags.synchronous ? nil : (_ASDisplayView *)self.view;
} }
// Returns nil if the layer is not an _ASDisplayLayer; will not create the view if nil // Returns nil if the layer is not an _ASDisplayLayer; will not create the layer if nil.
- (_ASDisplayLayer *)asyncLayer - (_ASDisplayLayer *)asyncLayer
{ {
ASDN::MutexLocker l(_propertyLock); ASDN::MutexLocker l(_propertyLock);
@ -317,17 +314,17 @@ void ASDisplayNodePerformBlockOnMainThread(void (^block)())
- (BOOL)isNodeLoaded - (BOOL)isNodeLoaded
{ {
ASDN::MutexLocker l(_propertyLock); ASDN::MutexLocker l(_propertyLock);
return (_view != nil || (_flags.isLayerBacked && _layer != nil)); return (_view != nil || (_flags.layerBacked && _layer != nil));
} }
- (BOOL)isSynchronous - (BOOL)isSynchronous
{ {
return _flags.isSynchronous; return _flags.synchronous;
} }
- (void)setSynchronous:(BOOL)flag - (void)setSynchronous:(BOOL)flag
{ {
_flags.isSynchronous = flag; _flags.synchronous = flag;
} }
- (void)setLayerBacked:(BOOL)isLayerBacked - (void)setLayerBacked:(BOOL)isLayerBacked
@ -336,15 +333,15 @@ void ASDisplayNodePerformBlockOnMainThread(void (^block)())
ASDN::MutexLocker l(_propertyLock); ASDN::MutexLocker l(_propertyLock);
ASDisplayNodeAssert(!_view && !_layer, @"Cannot change isLayerBacked after layer or view has loaded"); ASDisplayNodeAssert(!_view && !_layer, @"Cannot change isLayerBacked after layer or view has loaded");
if (isLayerBacked != _flags.isLayerBacked && !_view && !_layer) { if (isLayerBacked != _flags.layerBacked && !_view && !_layer) {
_flags.isLayerBacked = isLayerBacked; _flags.layerBacked = isLayerBacked;
} }
} }
- (BOOL)isLayerBacked - (BOOL)isLayerBacked
{ {
ASDN::MutexLocker l(_propertyLock); ASDN::MutexLocker l(_propertyLock);
return _flags.isLayerBacked; return _flags.layerBacked;
} }
#pragma mark - #pragma mark -
@ -360,10 +357,10 @@ void ASDisplayNodePerformBlockOnMainThread(void (^block)())
// - we haven't already // - we haven't already
// - the width is different from the last time // - the width is different from the last time
// - the height is different from the last time // - the height is different from the last time
if (!_flags.sizeCalculated || !CGSizeEqualToSize(constrainedSize, _constrainedSize)) { if (!_flags.isMeasured || !CGSizeEqualToSize(constrainedSize, _constrainedSize)) {
_size = [self calculateSizeThatFits:constrainedSize]; _size = [self calculateSizeThatFits:constrainedSize];
_constrainedSize = constrainedSize; _constrainedSize = constrainedSize;
_flags.sizeCalculated = YES; _flags.isMeasured = YES;
} }
ASDisplayNodeAssertTrue(_size.width >= 0.0); ASDisplayNodeAssertTrue(_size.width >= 0.0);
@ -387,7 +384,7 @@ void ASDisplayNodePerformBlockOnMainThread(void (^block)())
ASDisplayNodeAssertThreadAffinity(self); ASDisplayNodeAssertThreadAffinity(self);
// Can't do this for synchronous nodes (using layers that are not _ASDisplayLayer and so we can't control display prevention/cancel) // Can't do this for synchronous nodes (using layers that are not _ASDisplayLayer and so we can't control display prevention/cancel)
if (_flags.isSynchronous) if (_flags.synchronous)
return; return;
ASDN::MutexLocker l(_propertyLock); ASDN::MutexLocker l(_propertyLock);
@ -467,7 +464,7 @@ void ASDisplayNodePerformBlockOnMainThread(void (^block)())
- (void)displayImmediately - (void)displayImmediately
{ {
ASDisplayNodeAssertMainThread(); ASDisplayNodeAssertMainThread();
ASDisplayNodeAssert(!_flags.isSynchronous, @"this method is designed for asynchronous mode only"); ASDisplayNodeAssert(!_flags.synchronous, @"this method is designed for asynchronous mode only");
[[self asyncLayer] displayImmediately]; [[self asyncLayer] displayImmediately];
} }
@ -631,6 +628,10 @@ static inline CATransform3D _calculateTransformFromReferenceToTarget(ASDisplayNo
#pragma mark - _ASDisplayLayerDelegate #pragma mark - _ASDisplayLayerDelegate
- (void)willDisplayAsyncLayer:(_ASDisplayLayer *)layer
{
}
- (void)didDisplayAsyncLayer:(_ASDisplayLayer *)layer - (void)didDisplayAsyncLayer:(_ASDisplayLayer *)layer
{ {
// Subclass hook. // Subclass hook.
@ -648,7 +649,7 @@ static inline CATransform3D _calculateTransformFromReferenceToTarget(ASDisplayNo
[self __exitHierarchy]; [self __exitHierarchy];
} }
ASDisplayNodeAssert(_flags.isLayerBacked, @"We shouldn't get called back here if there is no layer"); ASDisplayNodeAssert(_flags.layerBacked, @"We shouldn't get called back here if there is no layer");
return (id<CAAction>)[NSNull null]; return (id<CAAction>)[NSNull null];
} }
@ -657,9 +658,9 @@ static inline CATransform3D _calculateTransformFromReferenceToTarget(ASDisplayNo
static bool disableNotificationsForMovingBetweenParents(ASDisplayNode *from, ASDisplayNode *to) static bool disableNotificationsForMovingBetweenParents(ASDisplayNode *from, ASDisplayNode *to)
{ {
if (!from || !to) return NO; if (!from || !to) return NO;
if (from->_flags.isSynchronous) return NO; if (from->_flags.synchronous) return NO;
if (to->_flags.isSynchronous) return NO; if (to->_flags.synchronous) return NO;
if (from->_flags.inWindow != to->_flags.inWindow) return NO; if (from->_flags.isInWindow != to->_flags.isInWindow) return NO;
return YES; return YES;
} }
@ -960,14 +961,14 @@ static NSInteger incrementIfFound(NSInteger i) {
[_supernode _removeSubnode:self]; [_supernode _removeSubnode:self];
if (ASDisplayNodeThreadIsMain()) { if (ASDisplayNodeThreadIsMain()) {
if (_flags.isLayerBacked) { if (_flags.layerBacked) {
[_layer removeFromSuperlayer]; [_layer removeFromSuperlayer];
} else { } else {
[_view removeFromSuperview]; [_view removeFromSuperview];
} }
} else { } else {
dispatch_async(dispatch_get_main_queue(), ^{ dispatch_async(dispatch_get_main_queue(), ^{
if (_flags.isLayerBacked) { if (_flags.layerBacked) {
[_layer removeFromSuperlayer]; [_layer removeFromSuperlayer];
} else { } else {
[_view removeFromSuperview]; [_view removeFromSuperview];
@ -985,7 +986,7 @@ static NSInteger incrementIfFound(NSInteger i) {
- (void)__incrementVisibilityNotificationsDisabled - (void)__incrementVisibilityNotificationsDisabled
{ {
ASDN::MutexLocker l(_propertyLock); ASDN::MutexLocker l(_propertyLock);
const size_t maxVisibilityIncrement = (1ULL<<visibilityNotificationsDisabledBits) - 1ULL; const size_t maxVisibilityIncrement = (1ULL<<VISIBILITY_NOTIFICATIONS_DISABLED_BITS) - 1ULL;
ASDisplayNodeAssert(_flags.visibilityNotificationsDisabled < maxVisibilityIncrement, @"Oops, too many increments of the visibility notifications API"); ASDisplayNodeAssert(_flags.visibilityNotificationsDisabled < maxVisibilityIncrement, @"Oops, too many increments of the visibility notifications API");
if (_flags.visibilityNotificationsDisabled < maxVisibilityIncrement) if (_flags.visibilityNotificationsDisabled < maxVisibilityIncrement)
_flags.visibilityNotificationsDisabled++; _flags.visibilityNotificationsDisabled++;
@ -1019,17 +1020,17 @@ static NSInteger incrementIfFound(NSInteger i) {
- (void)__enterHierarchy - (void)__enterHierarchy
{ {
ASDisplayNodeAssertMainThread(); ASDisplayNodeAssertMainThread();
ASDisplayNodeAssert(!_flags.isInEnterHierarchy, @"Should not cause recursive __enterHierarchy"); ASDisplayNodeAssert(!_flags.isEnteringHierarchy, @"Should not cause recursive __enterHierarchy");
if (!self.inWindow && !_flags.visibilityNotificationsDisabled && ![self __hasParentWithVisibilityNotificationsDisabled]) { if (!self.inWindow && !_flags.visibilityNotificationsDisabled && ![self __hasParentWithVisibilityNotificationsDisabled]) {
self.inWindow = YES; self.inWindow = YES;
_flags.isInEnterHierarchy = YES; _flags.isEnteringHierarchy = YES;
if (self.shouldRasterizeDescendants) { if (self.shouldRasterizeDescendants) {
// Nodes that are descendants of a rasterized container do not have views or layers, and so cannot receive visibility notifications directly via orderIn/orderOut CALayer actions. Manually send visibility notifications to rasterized descendants. // Nodes that are descendants of a rasterized container do not have views or layers, and so cannot receive visibility notifications directly via orderIn/orderOut CALayer actions. Manually send visibility notifications to rasterized descendants.
[self _recursiveWillEnterHierarchy]; [self _recursiveWillEnterHierarchy];
} else { } else {
[self willEnterHierarchy]; [self willEnterHierarchy];
} }
_flags.isInEnterHierarchy = NO; _flags.isEnteringHierarchy = NO;
CALayer *layer = self.layer; CALayer *layer = self.layer;
if (!self.layer.contents) { if (!self.layer.contents) {
@ -1041,20 +1042,20 @@ static NSInteger incrementIfFound(NSInteger i) {
- (void)__exitHierarchy - (void)__exitHierarchy
{ {
ASDisplayNodeAssertMainThread(); ASDisplayNodeAssertMainThread();
ASDisplayNodeAssert(!_flags.isInExitHierarchy, @"Should not cause recursive __exitHierarchy"); ASDisplayNodeAssert(!_flags.isExitingHierarchy, @"Should not cause recursive __exitHierarchy");
if (self.inWindow && !_flags.visibilityNotificationsDisabled && ![self __hasParentWithVisibilityNotificationsDisabled]) { if (self.inWindow && !_flags.visibilityNotificationsDisabled && ![self __hasParentWithVisibilityNotificationsDisabled]) {
self.inWindow = NO; self.inWindow = NO;
[self.asyncLayer cancelAsyncDisplay]; [self.asyncLayer cancelAsyncDisplay];
_flags.isInExitHierarchy = YES; _flags.isExitingHierarchy = YES;
if (self.shouldRasterizeDescendants) { if (self.shouldRasterizeDescendants) {
// Nodes that are descendants of a rasterized container do not have views or layers, and so cannot receive visibility notifications directly via orderIn/orderOut CALayer actions. Manually send visibility notifications to rasterized descendants. // Nodes that are descendants of a rasterized container do not have views or layers, and so cannot receive visibility notifications directly via orderIn/orderOut CALayer actions. Manually send visibility notifications to rasterized descendants.
[self _recursiveDidExitHierarchy]; [self _recursiveDidExitHierarchy];
} else { } else {
[self didExitHierarchy]; [self didExitHierarchy];
} }
_flags.isInExitHierarchy = NO; _flags.isExitingHierarchy = NO;
} }
} }
@ -1064,9 +1065,9 @@ static NSInteger incrementIfFound(NSInteger i) {
return; return;
} }
_flags.isInEnterHierarchy = YES; _flags.isEnteringHierarchy = YES;
[self willEnterHierarchy]; [self willEnterHierarchy];
_flags.isInEnterHierarchy = NO; _flags.isEnteringHierarchy = NO;
for (ASDisplayNode *subnode in self.subnodes) { for (ASDisplayNode *subnode in self.subnodes) {
[subnode _recursiveWillEnterHierarchy]; [subnode _recursiveWillEnterHierarchy];
@ -1079,9 +1080,9 @@ static NSInteger incrementIfFound(NSInteger i) {
return; return;
} }
_flags.isInExitHierarchy = YES; _flags.isExitingHierarchy = YES;
[self didExitHierarchy]; [self didExitHierarchy];
_flags.isInExitHierarchy = NO; _flags.isExitingHierarchy = NO;
for (ASDisplayNode *subnode in self.subnodes) { for (ASDisplayNode *subnode in self.subnodes) {
[subnode _recursiveDidExitHierarchy]; [subnode _recursiveDidExitHierarchy];
@ -1139,7 +1140,7 @@ static NSInteger incrementIfFound(NSInteger i) {
{ {
ASDisplayNodeAssertThreadAffinity(self); ASDisplayNodeAssertThreadAffinity(self);
// This will cause -measure: to actually compute the size instead of returning the previously cached size // This will cause -measure: to actually compute the size instead of returning the previously cached size
_flags.sizeCalculated = NO; _flags.isMeasured = NO;
} }
- (void)didLoad - (void)didLoad
@ -1150,15 +1151,15 @@ static NSInteger incrementIfFound(NSInteger i) {
- (void)willEnterHierarchy - (void)willEnterHierarchy
{ {
ASDisplayNodeAssertMainThread(); ASDisplayNodeAssertMainThread();
ASDisplayNodeAssert(_flags.isInEnterHierarchy, @"You should never call -willEnterHierarchy directly. Appearance is automatically managed by ASDisplayNode"); ASDisplayNodeAssert(_flags.isEnteringHierarchy, @"You should never call -willEnterHierarchy directly. Appearance is automatically managed by ASDisplayNode");
ASDisplayNodeAssert(!_flags.isInExitHierarchy, @"ASDisplayNode inconsistency. __enterHierarchy and __exitHierarchy are mutually exclusive"); ASDisplayNodeAssert(!_flags.isExitingHierarchy, @"ASDisplayNode inconsistency. __enterHierarchy and __exitHierarchy are mutually exclusive");
} }
- (void)didExitHierarchy - (void)didExitHierarchy
{ {
ASDisplayNodeAssertMainThread(); ASDisplayNodeAssertMainThread();
ASDisplayNodeAssert(_flags.isInExitHierarchy, @"You should never call -didExitHierarchy directly. Appearance is automatically managed by ASDisplayNode"); ASDisplayNodeAssert(_flags.isExitingHierarchy, @"You should never call -didExitHierarchy directly. Appearance is automatically managed by ASDisplayNode");
ASDisplayNodeAssert(!_flags.isInEnterHierarchy, @"ASDisplayNode inconsistency. __enterHierarchy and __exitHierarchy are mutually exclusive"); ASDisplayNodeAssert(!_flags.isEnteringHierarchy, @"ASDisplayNode inconsistency. __enterHierarchy and __exitHierarchy are mutually exclusive");
[self __exitedHierarchy]; [self __exitedHierarchy];
} }
@ -1316,7 +1317,7 @@ static NSInteger incrementIfFound(NSInteger i) {
// for the view/layer are still valid. // for the view/layer are still valid.
ASDN::MutexLocker l(_propertyLock); ASDN::MutexLocker l(_propertyLock);
if (_flags.isLayerBacked) { if (_flags.layerBacked) {
[_pendingViewState applyToLayer:_layer]; [_pendingViewState applyToLayer:_layer];
} else { } else {
[_pendingViewState applyToView:_view]; [_pendingViewState applyToView:_view];
@ -1403,7 +1404,7 @@ static void _recursiveSetPreventOrCancelDisplay(ASDisplayNode *node, CALayer *la
ASDisplayNodeAssertThreadAffinity(self); ASDisplayNodeAssertThreadAffinity(self);
// Can't do this for synchronous nodes (using layers that are not _ASDisplayLayer and so we can't control display prevention/cancel) // Can't do this for synchronous nodes (using layers that are not _ASDisplayLayer and so we can't control display prevention/cancel)
if (_flags.isSynchronous) if (_flags.synchronous)
return; return;
ASDN::MutexLocker l(_propertyLock); ASDN::MutexLocker l(_propertyLock);
@ -1421,7 +1422,7 @@ static void _recursiveSetPreventOrCancelDisplay(ASDisplayNode *node, CALayer *la
ASDisplayNodeAssertThreadAffinity(self); ASDisplayNodeAssertThreadAffinity(self);
ASDN::MutexLocker l(_propertyLock); ASDN::MutexLocker l(_propertyLock);
return _flags.inWindow; return _flags.isInWindow;
} }
- (void)setInWindow:(BOOL)inWindow - (void)setInWindow:(BOOL)inWindow
@ -1429,7 +1430,7 @@ static void _recursiveSetPreventOrCancelDisplay(ASDisplayNode *node, CALayer *la
ASDisplayNodeAssertThreadAffinity(self); ASDisplayNodeAssertThreadAffinity(self);
ASDN::MutexLocker l(_propertyLock); ASDN::MutexLocker l(_propertyLock);
_flags.inWindow = inWindow; _flags.isInWindow = inWindow;
} }
+ (dispatch_queue_t)asyncSizingQueue + (dispatch_queue_t)asyncSizingQueue
@ -1507,7 +1508,7 @@ static void _recursiveSetPreventOrCancelDisplay(ASDisplayNode *node, CALayer *la
- (NSString *)debugDescription - (NSString *)debugDescription
{ {
NSString *notableTargetDesc = (_flags.isLayerBacked ? @" [layer]" : @" [view]"); NSString *notableTargetDesc = (_flags.layerBacked ? @" [layer]" : @" [view]");
if (_view && _viewClass) { // Nonstandard view is loaded if (_view && _viewClass) { // Nonstandard view is loaded
notableTargetDesc = [NSString stringWithFormat:@" [%@ : %p]", _view.class, _view]; notableTargetDesc = [NSString stringWithFormat:@" [%@ : %p]", _view.class, _view];
} else if (_layer && _layerClass) { // Nonstandard layer is loaded } else if (_layer && _layerClass) { // Nonstandard layer is loaded

View File

@ -72,7 +72,7 @@ static void __ASDisplayLayerDecrementConcurrentDisplayCount(BOOL displayIsAsync,
- (NSObject *)drawParameters - (NSObject *)drawParameters
{ {
if (_flags.hasDrawParametersForAsyncLayer) { if (_flags.implementsDrawParameters) {
return [self drawParametersForAsyncLayer:self.asyncLayer]; return [self drawParametersForAsyncLayer:self.asyncLayer];
} }
@ -197,7 +197,7 @@ static void __ASDisplayLayerDecrementConcurrentDisplayCount(BOOL displayIsAsync,
return image; return image;
}; };
} else if (_flags.hasClassDisplay) { } else if (_flags.implementsImageDisplay) {
// Capture drawParameters from delegate on main thread // Capture drawParameters from delegate on main thread
id drawParameters = [self drawParameters]; id drawParameters = [self drawParameters];
@ -213,7 +213,7 @@ static void __ASDisplayLayerDecrementConcurrentDisplayCount(BOOL displayIsAsync,
return result; return result;
}; };
} else if (_flags.implementsDisplay) { } else if (_flags.implementsDrawRect) {
CGRect bounds = self.bounds; CGRect bounds = self.bounds;
if (CGRectIsEmpty(bounds)) { if (CGRectIsEmpty(bounds)) {
@ -317,9 +317,7 @@ static void __ASDisplayLayerDecrementConcurrentDisplayCount(BOOL displayIsAsync,
if (displayBlock != NULL) { if (displayBlock != NULL) {
// Call willDisplay immediately in either case // Call willDisplay immediately in either case
if (_flags.hasWillDisplayAsyncLayer) { [self willDisplayAsyncLayer:self.asyncLayer];
[self willDisplayAsyncLayer:self.asyncLayer];
}
if (asynchronously) { if (asynchronously) {
[transaction addOperationWithBlock:displayBlock queue:[_ASDisplayLayer displayQueue] completion:completionBlock]; [transaction addOperationWithBlock:displayBlock queue:[_ASDisplayLayer displayQueue] completion:completionBlock];

View File

@ -186,7 +186,7 @@
- (BOOL)isUserInteractionEnabled - (BOOL)isUserInteractionEnabled
{ {
_bridge_prologue; _bridge_prologue;
if (_flags.isLayerBacked) return NO; if (_flags.layerBacked) return NO;
return _getFromViewOnly(userInteractionEnabled); return _getFromViewOnly(userInteractionEnabled);
} }
@ -319,28 +319,28 @@
- (BOOL)autoresizesSubviews - (BOOL)autoresizesSubviews
{ {
_bridge_prologue; _bridge_prologue;
ASDisplayNodeAssert(!_flags.isLayerBacked, @"Danger: this property is undefined on layer-backed nodes."); ASDisplayNodeAssert(!_flags.layerBacked, @"Danger: this property is undefined on layer-backed nodes.");
return _getFromViewOnly(autoresizesSubviews); return _getFromViewOnly(autoresizesSubviews);
} }
- (void)setAutoresizesSubviews:(BOOL)flag - (void)setAutoresizesSubviews:(BOOL)flag
{ {
_bridge_prologue; _bridge_prologue;
ASDisplayNodeAssert(!_flags.isLayerBacked, @"Danger: this property is undefined on layer-backed nodes."); ASDisplayNodeAssert(!_flags.layerBacked, @"Danger: this property is undefined on layer-backed nodes.");
_setToViewOnly(autoresizesSubviews, flag); _setToViewOnly(autoresizesSubviews, flag);
} }
- (UIViewAutoresizing)autoresizingMask - (UIViewAutoresizing)autoresizingMask
{ {
_bridge_prologue; _bridge_prologue;
ASDisplayNodeAssert(!_flags.isLayerBacked, @"Danger: this property is undefined on layer-backed nodes."); ASDisplayNodeAssert(!_flags.layerBacked, @"Danger: this property is undefined on layer-backed nodes.");
return _getFromViewOnly(autoresizingMask); return _getFromViewOnly(autoresizingMask);
} }
- (void)setAutoresizingMask:(UIViewAutoresizing)mask - (void)setAutoresizingMask:(UIViewAutoresizing)mask
{ {
_bridge_prologue; _bridge_prologue;
ASDisplayNodeAssert(!_flags.isLayerBacked, @"Danger: this property is undefined on layer-backed nodes."); ASDisplayNodeAssert(!_flags.layerBacked, @"Danger: this property is undefined on layer-backed nodes.");
_setToViewOnly(autoresizingMask, mask); _setToViewOnly(autoresizingMask, mask);
} }
@ -379,14 +379,14 @@
- (UIColor *)tintColor - (UIColor *)tintColor
{ {
_bridge_prologue; _bridge_prologue;
ASDisplayNodeAssert(!_flags.isLayerBacked, @"Danger: this property is undefined on layer-backed nodes."); ASDisplayNodeAssert(!_flags.layerBacked, @"Danger: this property is undefined on layer-backed nodes.");
return _getFromViewOnly(tintColor); return _getFromViewOnly(tintColor);
} }
- (void)setTintColor:(UIColor *)color - (void)setTintColor:(UIColor *)color
{ {
_bridge_prologue; _bridge_prologue;
ASDisplayNodeAssert(!_flags.isLayerBacked, @"Danger: this property is undefined on layer-backed nodes."); ASDisplayNodeAssert(!_flags.layerBacked, @"Danger: this property is undefined on layer-backed nodes.");
_setToViewOnly(tintColor, color); _setToViewOnly(tintColor, color);
} }

View File

@ -25,14 +25,15 @@ void ASDisplayNodePerformBlockOnMainThread(void (^block)());
@class _ASPendingState; @class _ASPendingState;
// Allow 2^n increments of begin disabling hierarchy notifications // Allow 2^n increments of begin disabling hierarchy notifications
#define visibilityNotificationsDisabledBits 4 #define VISIBILITY_NOTIFICATIONS_DISABLED_BITS 4
#define TIME_DISPLAYNODE_OPS (DEBUG || PROFILE) #define TIME_DISPLAYNODE_OPS (DEBUG || PROFILE)
@interface ASDisplayNode () <_ASDisplayLayerDelegate> @interface ASDisplayNode () <_ASDisplayLayerDelegate>
{ {
@protected @protected
ASDN::RecursiveMutex _propertyLock; // Protects access to the _view, _pendingViewState, _subnodes, _supernode, _renderingSubnodes, and other properties which are accessed from multiple threads. // Protects access to _view, _layer, _pendingViewState, _subnodes, _supernode, and other properties which are accessed from multiple threads.
ASDN::RecursiveMutex _propertyLock;
ASDisplayNode * __weak _supernode; ASDisplayNode * __weak _supernode;
@ -55,20 +56,24 @@ void ASDisplayNodePerformBlockOnMainThread(void (^block)());
_ASPendingState *_pendingViewState; _ASPendingState *_pendingViewState;
struct { struct {
unsigned implementsDisplay:1; // public properties
unsigned isSynchronous:1; unsigned synchronous:1;
unsigned isLayerBacked:1; unsigned layerBacked:1;
unsigned sizeCalculated:1;
unsigned preventOrCancelDisplay:1;
unsigned displaysAsynchronously:1; unsigned displaysAsynchronously:1;
unsigned shouldRasterizeDescendants:1; unsigned shouldRasterizeDescendants:1;
unsigned visibilityNotificationsDisabled:visibilityNotificationsDisabledBits; unsigned preventOrCancelDisplay:1;
unsigned isInEnterHierarchy:1;
unsigned isInExitHierarchy:1; // whether custom drawing is enabled
unsigned inWindow:1; unsigned implementsDrawRect:1;
unsigned hasWillDisplayAsyncLayer:1; unsigned implementsImageDisplay:1;
unsigned hasDrawParametersForAsyncLayer:1; unsigned implementsDrawParameters:1;
unsigned hasClassDisplay:1;
// internal state
unsigned isMeasured:1;
unsigned isEnteringHierarchy:1;
unsigned isExitingHierarchy:1;
unsigned isInWindow:1;
unsigned visibilityNotificationsDisabled:VISIBILITY_NOTIFICATIONS_DISABLED_BITS;
} _flags; } _flags;
ASDisplayNodeExtraIvars _extra; ASDisplayNodeExtraIvars _extra;
@ -100,7 +105,7 @@ void ASDisplayNodePerformBlockOnMainThread(void (^block)());
// The visibility state of the node. Changed before calling willAppear, willDisappear, and didDisappear. // The visibility state of the node. Changed before calling willAppear, willDisappear, and didDisappear.
@property (nonatomic, readwrite, assign, getter = isInWindow) BOOL inWindow; @property (nonatomic, readwrite, assign, getter = isInWindow) BOOL inWindow;
// Private API for helper funcitons / unit tests. Use ASDisplayNodeDisableHierarchyNotifications() to control this. // Private API for helper functions / unit tests. Use ASDisplayNodeDisableHierarchyNotifications() to control this.
- (BOOL)__visibilityNotificationsDisabled; - (BOOL)__visibilityNotificationsDisabled;
- (void)__incrementVisibilityNotificationsDisabled; - (void)__incrementVisibilityNotificationsDisabled;
- (void)__decrementVisibilityNotificationsDisabled; - (void)__decrementVisibilityNotificationsDisabled;