Add locking for ASInterfaceState. Misc. cleanup.

This commit is contained in:
Scott Goodson 2015-11-29 14:57:43 -08:00
parent fb9f37b293
commit 254f55b758
5 changed files with 68 additions and 65 deletions

View File

@ -379,11 +379,6 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c)
return YES; return YES;
} }
- (void)__exitedHierarchy
{
}
- (UIView *)_viewToLoad - (UIView *)_viewToLoad
{ {
UIView *view; UIView *view;
@ -787,55 +782,9 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c)
return transform; return transform;
} }
static inline BOOL _ASDisplayNodeIsAncestorOfDisplayNode(ASDisplayNode *possibleAncestor, ASDisplayNode *possibleDescendent)
{
ASDisplayNode *supernode = possibleDescendent;
while (supernode) {
if (supernode == possibleAncestor) {
return YES;
}
supernode = supernode.supernode;
}
return NO;
}
/**
* NOTE: It is an error to try to convert between nodes which do not share a common ancestor. This behavior is
* disallowed in UIKit documentation and the behavior is left undefined. The output does not have a rigorously defined
* failure mode (i.e. returning CGPointZero or returning the point exactly as passed in). Rather than track the internal
* undefined and undocumented behavior of UIKit in ASDisplayNode, this operation is defined to be incorrect in all
* circumstances and must be fixed wherever encountered.
*/
static inline ASDisplayNode *_ASDisplayNodeFindClosestCommonAncestor(ASDisplayNode *node1, ASDisplayNode *node2)
{
ASDisplayNode *possibleAncestor = node1;
while (possibleAncestor) {
if (_ASDisplayNodeIsAncestorOfDisplayNode(possibleAncestor, node2)) {
break;
}
possibleAncestor = possibleAncestor.supernode;
}
ASDisplayNodeCAssertNotNil(possibleAncestor, @"Could not find a common ancestor between node1: %@ and node2: %@", node1, node2);
return possibleAncestor;
}
static inline ASDisplayNode *_getRootNode(ASDisplayNode *node)
{
// node <- supernode on each loop
// previous <- node on each loop where node is not nil
// previous is the final non-nil value of supernode, i.e. the root node
ASDisplayNode *previousNode = node;
while ((node = [node supernode])) {
previousNode = node;
}
return previousNode;
}
static inline CATransform3D _calculateTransformFromReferenceToTarget(ASDisplayNode *referenceNode, ASDisplayNode *targetNode) static inline CATransform3D _calculateTransformFromReferenceToTarget(ASDisplayNode *referenceNode, ASDisplayNode *targetNode)
{ {
ASDisplayNode *ancestor = _ASDisplayNodeFindClosestCommonAncestor(referenceNode, targetNode); ASDisplayNode *ancestor = ASDisplayNodeFindClosestCommonAncestor(referenceNode, targetNode);
// Transform into global (away from reference coordinate space) // Transform into global (away from reference coordinate space)
CATransform3D transformToGlobal = [referenceNode _transformToAncestor:ancestor]; CATransform3D transformToGlobal = [referenceNode _transformToAncestor:ancestor];
@ -850,7 +799,7 @@ static inline CATransform3D _calculateTransformFromReferenceToTarget(ASDisplayNo
{ {
ASDisplayNodeAssertThreadAffinity(self); ASDisplayNodeAssertThreadAffinity(self);
// Get root node of the accessible node hierarchy, if node not specified // Get root node of the accessible node hierarchy, if node not specified
node = node ? node : _getRootNode(self); node = node ? node : ASDisplayNodeUltimateParentOfNode(self);
// Calculate transform to map points between coordinate spaces // Calculate transform to map points between coordinate spaces
CATransform3D nodeTransform = _calculateTransformFromReferenceToTarget(node, self); CATransform3D nodeTransform = _calculateTransformFromReferenceToTarget(node, self);
@ -865,7 +814,7 @@ static inline CATransform3D _calculateTransformFromReferenceToTarget(ASDisplayNo
{ {
ASDisplayNodeAssertThreadAffinity(self); ASDisplayNodeAssertThreadAffinity(self);
// Get root node of the accessible node hierarchy, if node not specified // Get root node of the accessible node hierarchy, if node not specified
node = node ? node : _getRootNode(self); node = node ? node : ASDisplayNodeUltimateParentOfNode(self);
// Calculate transform to map points between coordinate spaces // Calculate transform to map points between coordinate spaces
CATransform3D nodeTransform = _calculateTransformFromReferenceToTarget(self, node); CATransform3D nodeTransform = _calculateTransformFromReferenceToTarget(self, node);
@ -880,7 +829,7 @@ static inline CATransform3D _calculateTransformFromReferenceToTarget(ASDisplayNo
{ {
ASDisplayNodeAssertThreadAffinity(self); ASDisplayNodeAssertThreadAffinity(self);
// Get root node of the accessible node hierarchy, if node not specified // Get root node of the accessible node hierarchy, if node not specified
node = node ? node : _getRootNode(self); node = node ? node : ASDisplayNodeUltimateParentOfNode(self);
// Calculate transform to map points between coordinate spaces // Calculate transform to map points between coordinate spaces
CATransform3D nodeTransform = _calculateTransformFromReferenceToTarget(node, self); CATransform3D nodeTransform = _calculateTransformFromReferenceToTarget(node, self);
@ -895,7 +844,7 @@ static inline CATransform3D _calculateTransformFromReferenceToTarget(ASDisplayNo
{ {
ASDisplayNodeAssertThreadAffinity(self); ASDisplayNodeAssertThreadAffinity(self);
// Get root node of the accessible node hierarchy, if node not specified // Get root node of the accessible node hierarchy, if node not specified
node = node ? node : _getRootNode(self); node = node ? node : ASDisplayNodeUltimateParentOfNode(self);
// Calculate transform to map points between coordinate spaces // Calculate transform to map points between coordinate spaces
CATransform3D nodeTransform = _calculateTransformFromReferenceToTarget(self, node); CATransform3D nodeTransform = _calculateTransformFromReferenceToTarget(self, node);
@ -1614,6 +1563,7 @@ void recursivelyEnsureDisplayForLayer(CALayer *layer)
- (void)__didLoad - (void)__didLoad
{ {
ASDN::MutexLocker l(_propertyLock);
if (_nodeLoadedBlock) { if (_nodeLoadedBlock) {
_nodeLoadedBlock(self); _nodeLoadedBlock(self);
_nodeLoadedBlock = nil; _nodeLoadedBlock = nil;
@ -1638,8 +1588,6 @@ void recursivelyEnsureDisplayForLayer(CALayer *layer)
ASDisplayNodeAssertMainThread(); ASDisplayNodeAssertMainThread();
ASDisplayNodeAssert(_flags.isExitingHierarchy, @"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.isEnteringHierarchy, @"ASDisplayNode inconsistency. __enterHierarchy and __exitHierarchy are mutually exclusive"); ASDisplayNodeAssert(!_flags.isEnteringHierarchy, @"ASDisplayNode inconsistency. __enterHierarchy and __exitHierarchy are mutually exclusive");
[self __exitedHierarchy];
} }
- (void)clearContents - (void)clearContents
@ -1689,11 +1637,13 @@ void recursivelyEnsureDisplayForLayer(CALayer *layer)
- (ASInterfaceState)interfaceState - (ASInterfaceState)interfaceState
{ {
ASDN::MutexLocker l(_propertyLock);
return _interfaceState; return _interfaceState;
} }
- (void)setInterfaceState:(ASInterfaceState)interfaceState - (void)setInterfaceState:(ASInterfaceState)interfaceState
{ {
ASDN::MutexLocker l(_propertyLock);
if (interfaceState != _interfaceState) { if (interfaceState != _interfaceState) {
if ((interfaceState & ASInterfaceStateMeasureLayout) != (_interfaceState & ASInterfaceStateMeasureLayout)) { if ((interfaceState & ASInterfaceStateMeasureLayout) != (_interfaceState & ASInterfaceStateMeasureLayout)) {
// Trigger asynchronous measurement if it is not already cached or being calculated. // Trigger asynchronous measurement if it is not already cached or being calculated.

View File

@ -24,13 +24,18 @@ extern ASDisplayNode *ASLayerToDisplayNode(CALayer *layer);
*/ */
extern ASDisplayNode *ASViewToDisplayNode(UIView *view); extern ASDisplayNode *ASViewToDisplayNode(UIView *view);
/**
Given a node, returns the root of the node heirarchy (where supernode == nil)
*/
extern ASDisplayNode *ASDisplayNodeUltimateParentOfNode(ASDisplayNode *node);
/** /**
This function will walk the layer heirarchy, spanning discontinuous sections of the node heirarchy (e.g. the layers This function will walk the layer heirarchy, spanning discontinuous sections of the node heirarchy (e.g. the layers
of UIKit intermediate views in UIViewControllers, UITableView, UICollectionView). of UIKit intermediate views in UIViewControllers, UITableView, UICollectionView).
In the event that a node's backing layer is not created yet, the function will only walk the direct subnodes instead In the event that a node's backing layer is not created yet, the function will only walk the direct subnodes instead
of forcing the layer heirarchy to be created. of forcing the layer heirarchy to be created.
*/ */
void ASDisplayNodePerformBlockOnEveryNode(CALayer *layer, ASDisplayNode *node, void(^block)(ASDisplayNode *node)); extern void ASDisplayNodePerformBlockOnEveryNode(CALayer *layer, ASDisplayNode *node, void(^block)(ASDisplayNode *node));
/** /**
Given a display node, traverses up the layer tree hierarchy, returning the first display node that passes block. Given a display node, traverses up the layer tree hierarchy, returning the first display node that passes block.
@ -42,6 +47,16 @@ extern id ASDisplayNodeFind(ASDisplayNode *node, BOOL (^block)(ASDisplayNode *no
*/ */
extern id ASDisplayNodeFindClass(ASDisplayNode *start, Class c); extern id ASDisplayNodeFindClass(ASDisplayNode *start, Class c);
/**
* Given two nodes, finds their most immediate common parent. Used for geometry conversion methods.
* NOTE: It is an error to try to convert between nodes which do not share a common ancestor. This behavior is
* disallowed in UIKit documentation and the behavior is left undefined. The output does not have a rigorously defined
* failure mode (i.e. returning CGPointZero or returning the point exactly as passed in). Rather than track the internal
* undefined and undocumented behavior of UIKit in ASDisplayNode, this operation is defined to be incorrect in all
* circumstances and must be fixed wherever encountered.
*/
extern ASDisplayNode *ASDisplayNodeFindClosestCommonAncestor(ASDisplayNode *node1, ASDisplayNode *node2);
/** /**
Given a display node, collects all descendents. This is a specialization of ASCollectContainer() that walks the Core Animation layer tree as opposed to the display node tree, thus supporting non-continues display node hierarchies. Given a display node, collects all descendents. This is a specialization of ASCollectContainer() that walks the Core Animation layer tree as opposed to the display node tree, thus supporting non-continues display node hierarchies.
*/ */

View File

@ -10,17 +10,17 @@
#import "ASDisplayNodeInternal.h" #import "ASDisplayNodeInternal.h"
inline ASDisplayNode *ASLayerToDisplayNode(CALayer *layer) extern ASDisplayNode *ASLayerToDisplayNode(CALayer *layer)
{ {
return layer.asyncdisplaykit_node; return layer.asyncdisplaykit_node;
} }
inline ASDisplayNode *ASViewToDisplayNode(UIView *view) extern ASDisplayNode *ASViewToDisplayNode(UIView *view)
{ {
return view.asyncdisplaykit_node; return view.asyncdisplaykit_node;
} }
void ASDisplayNodePerformBlockOnEveryNode(CALayer *layer, ASDisplayNode *node, void(^block)(ASDisplayNode *node)) extern void ASDisplayNodePerformBlockOnEveryNode(CALayer *layer, ASDisplayNode *node, void(^block)(ASDisplayNode *node))
{ {
if (!node) { if (!node) {
ASDisplayNodeCAssertNotNil(layer, @"Cannot recursively perform with nil node and nil layer"); ASDisplayNodeCAssertNotNil(layer, @"Cannot recursively perform with nil node and nil layer");
@ -148,6 +148,45 @@ extern id ASDisplayNodeFindFirstSubnodeOfClass(ASDisplayNode *start, Class c)
}); });
} }
static inline BOOL _ASDisplayNodeIsAncestorOfDisplayNode(ASDisplayNode *possibleAncestor, ASDisplayNode *possibleDescendent)
{
ASDisplayNode *supernode = possibleDescendent;
while (supernode) {
if (supernode == possibleAncestor) {
return YES;
}
supernode = supernode.supernode;
}
return NO;
}
extern ASDisplayNode *ASDisplayNodeFindClosestCommonAncestor(ASDisplayNode *node1, ASDisplayNode *node2)
{
ASDisplayNode *possibleAncestor = node1;
while (possibleAncestor) {
if (_ASDisplayNodeIsAncestorOfDisplayNode(possibleAncestor, node2)) {
break;
}
possibleAncestor = possibleAncestor.supernode;
}
ASDisplayNodeCAssertNotNil(possibleAncestor, @"Could not find a common ancestor between node1: %@ and node2: %@", node1, node2);
return possibleAncestor;
}
extern ASDisplayNode *ASDisplayNodeUltimateParentOfNode(ASDisplayNode *node)
{
// node <- supernode on each loop
// previous <- node on each loop where node is not nil
// previous is the final non-nil value of supernode, i.e. the root node
ASDisplayNode *previousNode = node;
while ((node = [node supernode])) {
previousNode = node;
}
return previousNode;
}
#pragma mark - Placeholders #pragma mark - Placeholders
UIColor *ASDisplayNodeDefaultPlaceholderColor() UIColor *ASDisplayNodeDefaultPlaceholderColor()

View File

@ -125,7 +125,6 @@ typedef NS_OPTIONS(NSUInteger, ASDisplayNodeMethodOverrides) {
// Swizzle to extend the builtin functionality with custom logic // Swizzle to extend the builtin functionality with custom logic
- (BOOL)__shouldLoadViewOrLayer; - (BOOL)__shouldLoadViewOrLayer;
- (BOOL)__shouldSize; - (BOOL)__shouldSize;
- (void)__exitedHierarchy;
// Core implementation of -measureWithSizeRange:. Must be called with _propertyLock held. // Core implementation of -measureWithSizeRange:. Must be called with _propertyLock held.
- (ASLayout *)__measureWithSizeRange:(ASSizeRange)constrainedSize; - (ASLayout *)__measureWithSizeRange:(ASSizeRange)constrainedSize;

View File

@ -266,7 +266,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES; GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 8.0; IPHONEOS_DEPLOYMENT_TARGET = 7.1;
MTL_ENABLE_DEBUG_INFO = YES; MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES; ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos; SDKROOT = iphoneos;
@ -301,7 +301,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES; GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 8.0; IPHONEOS_DEPLOYMENT_TARGET = 7.1;
MTL_ENABLE_DEBUG_INFO = NO; MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos; SDKROOT = iphoneos;
VALIDATE_PRODUCT = YES; VALIDATE_PRODUCT = YES;