Optimize insertion/deletion node calculation & expose inserted/deleted subnodes to transition context

This commit is contained in:
Levi McCallum
2016-02-10 11:08:30 -08:00
parent d669cadcba
commit 499c3331ce
5 changed files with 83 additions and 58 deletions

View File

@@ -30,6 +30,16 @@
*/
- (NSArray<ASDisplayNode *> *)subnodes;
/**
* @abstract Subnodes that have been inserted in the layout transition
*/
- (NSArray<ASDisplayNode *> *)insertedSubnodes;
/**
* @abstract Subnodes that will be removed in the layout transition
*/
- (NSArray<ASDisplayNode *> *)removedSubnodes;
/**
@abstract The frame for the given node before the transition began.
@discussion Returns CGRectNull if the node was not in the hierarchy before the transition.

View File

@@ -32,41 +32,6 @@ NSInteger const ASDefaultDrawingPriority = ASDefaultTransactionPriority;
NSString * const ASRenderingEngineDidDisplayScheduledNodesNotification = @"ASRenderingEngineDidDisplayScheduledNodes";
NSString * const ASRenderingEngineDidDisplayNodesScheduledBeforeTimestamp = @"ASRenderingEngineDidDisplayNodesScheduledBeforeTimestamp";
@interface _ASDisplayNodePosition : NSObject
@property (nonatomic, assign) NSUInteger index;
@property (nonatomic, strong) ASDisplayNode *node;
+ (instancetype)positionWithNode:(ASDisplayNode *)node atIndex:(NSUInteger)index;
- (instancetype)initWithNode:(ASDisplayNode *)node atIndex:(NSUInteger)index;
@end
@implementation _ASDisplayNodePosition
+ (instancetype)positionWithNode:(ASDisplayNode *)node atIndex:(NSUInteger)index
{
return [[self alloc] initWithNode:node atIndex:index];
}
- (instancetype)initWithNode:(ASDisplayNode *)node atIndex:(NSUInteger)index
{
self = [super init];
if (self) {
_node = node;
_index = index;
}
return self;
}
- (NSString *)description
{
return [NSString stringWithFormat:@"<%@ %p node = %@, index = %ld>", self.class, self, _node, (long)_index];
}
@end
@interface ASDisplayNode () <UIGestureRecognizerDelegate>
/**
@@ -703,12 +668,16 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c)
compareBlock:^BOOL(ASLayout *lhs, ASLayout *rhs) {
return ASObjectIsEqual(lhs.layoutableObject, rhs.layoutableObject);
}];
_insertedSubnodes = [self _nodesInLayout:pendingLayout atIndexes:insertions];
_deletedSubnodes = [self _nodesInLayout:currentLayout atIndexes:deletions filterNodes:_insertedSubnodes];
filterNodesInLayoutAtIndexes(pendingLayout, insertions, &_insertedSubnodes, &_insertedSubnodePositions);
filterNodesInLayoutAtIndexesWithIntersectingNodes(currentLayout,
deletions,
_insertedSubnodes,
&_removedSubnodes,
&_removedSubnodePositions);
} else {
NSIndexSet *indexes = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, [pendingLayout.immediateSublayouts count])];
_insertedSubnodes = [self _nodesInLayout:pendingLayout atIndexes:indexes];
_deletedSubnodes = nil;
filterNodesInLayoutAtIndexes(pendingLayout, indexes, &_insertedSubnodes, &_insertedSubnodePositions);
_removedSubnodes = nil;
}
}
@@ -721,6 +690,8 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c)
_layout = layout;
_constrainedSize = constrainedSize;
_flags.isMeasured = YES;
_insertedSubnodes = nil;
_removedSubnodes = nil;
[self calculatedLayoutDidChange];
// we generate placeholders at measureWithSizeRange: time so that a node is guaranteed
@@ -743,36 +714,51 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c)
}
/**
@abstract Retrieves nodes at the given indexes from the layout's sublayouts
* @abstract Stores the nodes at the given indexes in the `storedNodes` array, storing indexes in a `storedPositions` c++ vector.
*/
- (NSMutableArray<_ASDisplayNodePosition *> *)_nodesInLayout:(ASLayout *)layout atIndexes:(NSIndexSet *)indexes
static inline void filterNodesInLayoutAtIndexes(
ASLayout *layout,
NSIndexSet *indexes,
NSArray<ASDisplayNode *> * __strong *storedNodes,
std::vector<NSInteger> *storedPositions
)
{
return [self _nodesInLayout:layout atIndexes:indexes filterNodes:nil];
filterNodesInLayoutAtIndexesWithIntersectingNodes(layout, indexes, nil, storedNodes, storedPositions);
}
/**
@abstract Retrieves nodes at the given indexes from the layout's sublayouts, skipping nodes that are in the `filterNodes` list
* @abstract Stores the nodes at the given indexes in the `storedNodes` array, storing indexes in a `storedPositions` c++ vector.
* @discussion If the node exists in the `intersectingNodes` array, the node is not added to `storedNodes`.
*/
- (NSMutableArray<_ASDisplayNodePosition *> *)_nodesInLayout:(ASLayout *)layout atIndexes:(NSIndexSet *)indexes filterNodes:(NSArray<_ASDisplayNodePosition *> *)filterNodes
static inline void filterNodesInLayoutAtIndexesWithIntersectingNodes(
ASLayout *layout,
NSIndexSet *indexes,
NSArray<ASDisplayNode *> *intersectingNodes,
NSArray<ASDisplayNode *> * __strong *storedNodes,
std::vector<NSInteger> *storedPositions
)
{
NSMutableArray<_ASDisplayNodePosition *> *result = [NSMutableArray array];
NSMutableArray<ASDisplayNode *> *nodes = [NSMutableArray array];
std::vector<NSInteger> positions = std::vector<NSInteger>();
NSInteger idx = [indexes firstIndex];
while (idx != NSNotFound) {
BOOL skip = NO;
ASDisplayNode *node = (ASDisplayNode *)layout.immediateSublayouts[idx].layoutableObject;
ASDisplayNodeAssertNotNil(node, @"A flattened layout must consist exclusively of node sublayouts");
for (_ASDisplayNodePosition *filter in filterNodes) {
if (node == filter.node) {
ASDisplayNodeCAssert(node, @"A flattened layout must consist exclusively of node sublayouts");
for (ASDisplayNode *i in intersectingNodes) {
if (node == i) {
skip = YES;
break;
}
}
if (!skip) {
[result addObject:[_ASDisplayNodePosition positionWithNode:node atIndex:idx]];
[nodes addObject:node];
positions.push_back(idx);
}
idx = [indexes indexGreaterThanIndex:idx];
}
return result;
*storedNodes = nodes;
*storedPositions = positions;
}
- (void)calculatedLayoutDidChange
@@ -798,18 +784,17 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c)
- (void)__implicitlyInsertSubnodes
{
for (_ASDisplayNodePosition *position in _insertedSubnodes) {
[self insertSubnode:position.node atIndex:position.index];
for (NSInteger i = 0; i < [_insertedSubnodes count]; i++) {
NSInteger p = _insertedSubnodePositions[i];
[self insertSubnode:_insertedSubnodes[i] atIndex:p];
}
_insertedSubnodes = nil;
}
- (void)__implicitlyRemoveSubnodes
{
for (_ASDisplayNodePosition *position in _deletedSubnodes) {
[position.node removeFromSupernode];
for (NSInteger i = 0; i < [_insertedSubnodes count]; i++) {
[_removedSubnodes[i] removeFromSupernode];
}
_deletedSubnodes = nil;
}
#pragma mark - _ASTransitionContextDelegate
@@ -819,6 +804,16 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c)
return _subnodes;
}
- (NSArray<ASDisplayNode *> *)insertedSubnodesWithTransitionContext:(_ASTransitionContext *)context
{
return _insertedSubnodes;
}
- (NSArray<ASDisplayNode *> *)removedSubnodesWithTransitionContext:(_ASTransitionContext *)context
{
return _removedSubnodes;
}
- (void)transitionContext:(_ASTransitionContext *)context didComplete:(BOOL)didComplete
{
[self didCompleteTransitionLayout:context];

View File

@@ -19,6 +19,8 @@
#import "ASLayoutOptions.h"
#import "_ASTransitionContext.h"
#include <vector>
@protocol _ASDisplayLayerDelegate;
@class _ASDisplayLayer;
@@ -66,8 +68,11 @@ FOUNDATION_EXPORT NSString * const ASRenderingEngineDidDisplayNodesScheduledBefo
NSMutableArray *_subnodes;
_ASTransitionContext *_transitionContext;
NSArray<_ASDisplayNodePosition *> *_insertedSubnodes;
NSArray<_ASDisplayNodePosition *> *_deletedSubnodes;
NSArray<ASDisplayNode *> *_insertedSubnodes;
NSArray<ASDisplayNode *> *_removedSubnodes;
std::vector<NSInteger> _insertedSubnodePositions;
std::vector<NSInteger> _removedSubnodePositions;
ASDisplayNodeViewBlock _viewBlock;
ASDisplayNodeLayerBlock _layerBlock;

View File

@@ -16,6 +16,9 @@
@protocol _ASTransitionContextDelegate <NSObject>
- (NSArray<ASDisplayNode *> *)currentSubnodesWithTransitionContext:(_ASTransitionContext *)context;
- (NSArray<ASDisplayNode *> *)insertedSubnodesWithTransitionContext:(_ASTransitionContext *)context;
- (NSArray<ASDisplayNode *> *)removedSubnodesWithTransitionContext:(_ASTransitionContext *)context;
- (void)transitionContext:(_ASTransitionContext *)context didComplete:(BOOL)didComplete;
@end

View File

@@ -30,6 +30,8 @@
return self;
}
#pragma mark - ASContextTransitioning Protocol Implementation
- (CGRect)initialFrameForNode:(ASDisplayNode *)node
{
for (ASDisplayNode *subnode in [_delegate currentSubnodesWithTransitionContext:self]) {
@@ -59,6 +61,16 @@
return subnodes;
}
- (NSArray<ASDisplayNode *> *)insertedSubnodes
{
return [_delegate insertedSubnodesWithTransitionContext:self];
}
- (NSArray<ASDisplayNode *> *)removedSubnodes
{
return [_delegate removedSubnodesWithTransitionContext:self];
}
- (void)completeTransition:(BOOL)didComplete
{
[_delegate transitionContext:self didComplete:didComplete];