[ASDisplayNode] Ensure ASHierarchyState propagation does not jump discontinuities in the node hierarchy. (#2263)

Scenario: An ASCollectionNode is a subnode of an ASCellNode.  A layout transition is started, resulting in
the removal of the ASCollectionNode as a subnode.  As it is removed, the hierarchy state is cleared - including
the "range managed" bit - on the ASCollectionNode.  However, the deep recursion traverses the layer hierarchy
too, and clears this bit on the ASCellNodes inside the ASCollectionNode.  A moment later, the collection performs
its final ASRangeController update to mark its cells as invisible and free memory.  Then an assertion is triggered
in ASRangeController, because it is operating on nodes that do not have the "range managed" bit set.

It turns out that ASInterfaceState also propogates in this way, but that behavior is efficient and beneficial in
its current configuration (it assists how multi-dimensional preloading works).  However, hierarchy state should
never need to jump discontinuities in the node hierarchy.  For now, disabling that case and will revisit
other use cases soon.
This commit is contained in:
appleguy
2016-09-19 12:04:39 -07:00
committed by GitHub
parent 48f76c40d5
commit 3e5b8c3096
4 changed files with 29 additions and 29 deletions

View File

@@ -82,16 +82,16 @@ extern ASDisplayNode * _Nullable ASViewToDisplayNode(UIView * _Nullable view);
extern ASDisplayNode *ASDisplayNodeUltimateParentOfNode(ASDisplayNode *node);
/**
This function will walk the layer hierarchy, spanning discontinuous sections of the node hierarchy (e.g. the layers
of UIKit intermediate views in UIViewControllers, UITableView, UICollectionView).
If traverseSublayers == YES, this function will walk the layer hierarchy, spanning discontinuous sections of the node hierarchy\
(e.g. the layers 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
of forcing the layer hierarchy to be created.
*/
extern void ASDisplayNodePerformBlockOnEveryNode(CALayer * _Nullable layer, ASDisplayNode * _Nullable node, void(^block)(ASDisplayNode *node));
extern void ASDisplayNodePerformBlockOnEveryNode(CALayer * _Nullable layer, ASDisplayNode * _Nullable node, BOOL traverseSublayers, void(^block)(ASDisplayNode *node));
/**
This function will walk the node hierarchy in a breadth first fashion. It does run the block on the node provided
directly to the function call.
directly to the function call. It does NOT traverse sublayers.
*/
extern void ASDisplayNodePerformBlockOnEveryNodeBFS(ASDisplayNode *node, void(^block)(ASDisplayNode *node));
@@ -99,7 +99,7 @@ extern void ASDisplayNodePerformBlockOnEveryNodeBFS(ASDisplayNode *node, void(^b
Identical to ASDisplayNodePerformBlockOnEveryNode, except it does not run the block on the
node provided directly to the function call - only on all descendants.
*/
extern void ASDisplayNodePerformBlockOnEverySubnode(ASDisplayNode *node, void(^block)(ASDisplayNode *node));
extern void ASDisplayNodePerformBlockOnEverySubnode(ASDisplayNode *node, BOOL traverseSublayers, void(^block)(ASDisplayNode *node));
/**
Given a display node, traverses up the layer tree hierarchy, returning the first display node that passes block.