mirror of
https://github.com/HackPlan/AsyncDisplayKit.git
synced 2026-04-28 11:46:28 +08:00
[ASDisplayNode] Use a C function to lazily create pending view state
This commit is contained in:
@@ -79,6 +79,17 @@ BOOL ASDisplayNodeSubclassOverridesSelector(Class subclass, SEL selector)
|
||||
return ASSubclassOverridesSelector([ASDisplayNode class], subclass, selector);
|
||||
}
|
||||
|
||||
_ASPendingState *ASDisplayNodeGetPendingState(ASDisplayNode *node)
|
||||
{
|
||||
ASDN::MutexLocker l(node->_propertyLock);
|
||||
_ASPendingState *result = node->_pendingViewState;
|
||||
if (result == nil) {
|
||||
result = [[_ASPendingState alloc] init];
|
||||
node->_pendingViewState = result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns ASDisplayNodeFlags for the givern class/instance. instance MAY BE NIL.
|
||||
*
|
||||
@@ -257,7 +268,6 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c)
|
||||
_contentsScaleForDisplay = ASScreenScale();
|
||||
_displaySentinel = [[ASSentinel alloc] init];
|
||||
_preferredFrameSize = CGSizeZero;
|
||||
_pendingViewState = [_ASPendingState new];
|
||||
}
|
||||
|
||||
- (id)init
|
||||
|
||||
@@ -64,25 +64,23 @@ ASDISPLAYNODE_INLINE BOOL ASDisplayNodeShouldApplyBridgedWriteToView(ASDisplayNo
|
||||
|
||||
#define _getFromViewOrLayer(layerProperty, viewAndPendingViewStateProperty) __loaded ? \
|
||||
(_view ? _view.viewAndPendingViewStateProperty : _layer.layerProperty )\
|
||||
: self.pendingViewState.viewAndPendingViewStateProperty
|
||||
: ASDisplayNodeGetPendingState(self).viewAndPendingViewStateProperty
|
||||
|
||||
#define _setToViewOrLayer(layerProperty, layerValueExpr, viewAndPendingViewStateProperty, viewAndPendingViewStateExpr) BOOL shouldApply = ASDisplayNodeShouldApplyBridgedWriteToView(self); \
|
||||
if (shouldApply) { (_view ? _view.viewAndPendingViewStateProperty = (viewAndPendingViewStateExpr) : _layer.layerProperty = (layerValueExpr)); } else { _pendingViewState.viewAndPendingViewStateProperty = (viewAndPendingViewStateExpr); }
|
||||
if (shouldApply) { (_view ? _view.viewAndPendingViewStateProperty = (viewAndPendingViewStateExpr) : _layer.layerProperty = (layerValueExpr)); } else { ASDisplayNodeGetPendingState(self).viewAndPendingViewStateProperty = (viewAndPendingViewStateExpr); }
|
||||
|
||||
#define _setToViewOnly(viewAndPendingViewStateProperty, viewAndPendingViewStateExpr) BOOL shouldApply = ASDisplayNodeShouldApplyBridgedWriteToView(self); \
|
||||
if (shouldApply) { _view.viewAndPendingViewStateProperty = (viewAndPendingViewStateExpr); } else { _pendingViewState.viewAndPendingViewStateProperty = (viewAndPendingViewStateExpr); }
|
||||
if (shouldApply) { _view.viewAndPendingViewStateProperty = (viewAndPendingViewStateExpr); } else { ASDisplayNodeGetPendingState(self).viewAndPendingViewStateProperty = (viewAndPendingViewStateExpr); }
|
||||
|
||||
#define _getFromViewOnly(viewAndPendingViewStateProperty) __loaded ? _view.viewAndPendingViewStateProperty : self.pendingViewState.viewAndPendingViewStateProperty
|
||||
#define _getFromViewOnly(viewAndPendingViewStateProperty) __loaded ? _view.viewAndPendingViewStateProperty : ASDisplayNodeGetPendingState(self).viewAndPendingViewStateProperty
|
||||
|
||||
#define _getFromLayer(layerProperty) __loaded ? _layer.layerProperty : self.pendingViewState.layerProperty
|
||||
#define _getFromLayer(layerProperty) __loaded ? _layer.layerProperty : ASDisplayNodeGetPendingState(self).layerProperty
|
||||
|
||||
#define _setToLayer(layerProperty, layerValueExpr) BOOL shouldApply = ASDisplayNodeShouldApplyBridgedWriteToView(self); \
|
||||
if (shouldApply) { _layer.layerProperty = (layerValueExpr); } else { _pendingViewState.layerProperty = (layerValueExpr); }
|
||||
if (shouldApply) { _layer.layerProperty = (layerValueExpr); } else { ASDisplayNodeGetPendingState(self).layerProperty = (layerValueExpr); }
|
||||
|
||||
#define _messageToViewOrLayer(viewAndLayerSelector) (_view ? [_view viewAndLayerSelector] : [_layer viewAndLayerSelector])
|
||||
|
||||
#define _messageToLayer(layerSelector) __loaded ? [_layer layerSelector] : [self.pendingViewState layerSelector]
|
||||
|
||||
/**
|
||||
* This category implements certain frequently-used properties and methods of UIView and CALayer so that ASDisplayNode clients can just call the view/layer methods on the node,
|
||||
* with minimal loss in performance. Unlike UIView and CALayer methods, these can be called from a non-main thread until the view or layer is created.
|
||||
@@ -261,10 +259,11 @@ if (shouldApply) { _layer.layerProperty = (layerValueExpr); } else { _pendingVie
|
||||
self.bounds = bounds;
|
||||
self.position = position;
|
||||
} else if (nodeLoaded && !isMainThread) {
|
||||
if (!_pendingViewState.hasChanges) {
|
||||
[ASPendingStateController.sharedInstance registerNode:self];
|
||||
_ASPendingState *pendingState = ASDisplayNodeGetPendingState(self);
|
||||
if (!pendingState.hasChanges) {
|
||||
[[ASPendingStateController sharedInstance] registerNode:self];
|
||||
}
|
||||
_pendingViewState.frame = rect;
|
||||
pendingState.frame = rect;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -292,11 +291,12 @@ if (shouldApply) { _layer.layerProperty = (layerValueExpr); } else { _pendingVie
|
||||
if (ASDisplayNodeThreadIsMain()) {
|
||||
_messageToViewOrLayer(setNeedsDisplay);
|
||||
} else {
|
||||
if (!_pendingViewState.hasChanges) {
|
||||
[ASPendingStateController.sharedInstance registerNode:self];
|
||||
_ASPendingState *pendingState = ASDisplayNodeGetPendingState(self);
|
||||
if (!pendingState.hasChanges) {
|
||||
[[ASPendingStateController sharedInstance] registerNode:self];
|
||||
}
|
||||
[self __setNeedsDisplay];
|
||||
[_pendingViewState setNeedsDisplay];
|
||||
[pendingState setNeedsDisplay];
|
||||
}
|
||||
} else {
|
||||
[self __setNeedsDisplay];
|
||||
@@ -312,13 +312,14 @@ if (shouldApply) { _layer.layerProperty = (layerValueExpr); } else { _pendingVie
|
||||
[self __setNeedsLayout];
|
||||
_messageToViewOrLayer(setNeedsLayout);
|
||||
} else {
|
||||
if (!_pendingViewState.hasChanges) {
|
||||
[ASPendingStateController.sharedInstance registerNode:self];
|
||||
_ASPendingState *pendingState = ASDisplayNodeGetPendingState(self);
|
||||
if (!pendingState.hasChanges) {
|
||||
[[ASPendingStateController sharedInstance] registerNode:self];
|
||||
}
|
||||
// NOTE: We will call [self __setNeedsLayout] just before we apply
|
||||
// the pending state. We need to call it on main if the node is loaded
|
||||
// to support implicit hierarchy management.
|
||||
[_pendingViewState setNeedsLayout];
|
||||
[pendingState setNeedsLayout];
|
||||
}
|
||||
} else {
|
||||
[self __setNeedsLayout];
|
||||
@@ -511,21 +512,22 @@ if (shouldApply) { _layer.layerProperty = (layerValueExpr); } else { _pendingVie
|
||||
return _view.contentMode;
|
||||
}
|
||||
} else {
|
||||
return self.pendingViewState.contentMode;
|
||||
return ASDisplayNodeGetPendingState(self).contentMode;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setContentMode:(UIViewContentMode)contentMode
|
||||
{
|
||||
_bridge_prologue_write;
|
||||
if (__loaded) {
|
||||
BOOL shouldApply = ASDisplayNodeShouldApplyBridgedWriteToView(self);
|
||||
if (shouldApply) {
|
||||
if (_flags.layerBacked) {
|
||||
_layer.contentsGravity = ASDisplayNodeCAContentsGravityFromUIContentMode(contentMode);
|
||||
} else {
|
||||
_view.contentMode = contentMode;
|
||||
}
|
||||
} else {
|
||||
self.pendingViewState.contentMode = contentMode;
|
||||
ASDisplayNodeGetPendingState(self).contentMode = contentMode;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -23,9 +23,13 @@
|
||||
|
||||
@protocol _ASDisplayLayerDelegate;
|
||||
@class _ASDisplayLayer;
|
||||
@class _ASPendingState;
|
||||
|
||||
BOOL ASDisplayNodeSubclassOverridesSelector(Class subclass, SEL selector);
|
||||
|
||||
/// Get the pending view state for the node, creating one if needed.
|
||||
_ASPendingState *ASDisplayNodeGetPendingState(ASDisplayNode *node);
|
||||
|
||||
typedef NS_OPTIONS(NSUInteger, ASDisplayNodeMethodOverrides)
|
||||
{
|
||||
ASDisplayNodeMethodOverrideNone = 0,
|
||||
@@ -36,7 +40,6 @@ typedef NS_OPTIONS(NSUInteger, ASDisplayNodeMethodOverrides)
|
||||
ASDisplayNodeMethodOverrideLayoutSpecThatFits = 1 << 4
|
||||
};
|
||||
|
||||
@class _ASPendingState;
|
||||
@class _ASDisplayNodePosition;
|
||||
|
||||
FOUNDATION_EXPORT NSString * const ASRenderingEngineDidDisplayScheduledNodesNotification;
|
||||
@@ -139,9 +142,6 @@ FOUNDATION_EXPORT NSString * const ASRenderingEngineDidDisplayNodesScheduledBefo
|
||||
// The _ASDisplayLayer backing the node, if any.
|
||||
@property (nonatomic, readonly, retain) _ASDisplayLayer *asyncLayer;
|
||||
|
||||
// Creates a pendingViewState if one doesn't exist. Allows setting view properties on a bg thread before there is a view.
|
||||
@property (atomic, retain, readonly) _ASPendingState *pendingViewState;
|
||||
|
||||
// Bitmask to check which methods an object overrides.
|
||||
@property (nonatomic, assign, readonly) ASDisplayNodeMethodOverrides methodOverrides;
|
||||
|
||||
|
||||
@@ -168,13 +168,13 @@ static inline void ASDispatchSyncOnOtherThread(dispatch_block_t block) {
|
||||
{
|
||||
ASPendingStateController *ctrl = [ASPendingStateController sharedInstance];
|
||||
ASDisplayNode *node = [ASDisplayNode new];
|
||||
XCTAssertFalse(node.pendingViewState.hasChanges);
|
||||
XCTAssertFalse(ASDisplayNodeGetPendingState(node).hasChanges);
|
||||
[node view];
|
||||
XCTAssertEqual(node.alpha, 1);
|
||||
node.alpha = 0;
|
||||
XCTAssertEqual(node.view.alpha, 0);
|
||||
XCTAssertEqual(node.alpha, 0);
|
||||
XCTAssertFalse(node.pendingViewState.hasChanges);
|
||||
XCTAssertFalse(ASDisplayNodeGetPendingState(node).hasChanges);
|
||||
XCTAssertFalse(ctrl.test_isFlushScheduled);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user