From 19cc368d159992408a2a20fb7326924480292be9 Mon Sep 17 00:00:00 2001 From: Rahul Malik Date: Wed, 17 Feb 2016 13:19:00 -0800 Subject: [PATCH] In addition to allocating nodes in the background, perform that operation concurrently in ASDataController --- AsyncDisplayKit/ASCollectionView.mm | 4 ++- AsyncDisplayKit/ASTableView.mm | 6 +++-- AsyncDisplayKit/Details/ASDataController.mm | 27 ++++++++++++++++----- AsyncDisplayKitTests/ASDisplayNodeTests.m | 1 + 4 files changed, 29 insertions(+), 9 deletions(-) diff --git a/AsyncDisplayKit/ASCollectionView.mm b/AsyncDisplayKit/ASCollectionView.mm index b9f58ee5ff..3d80ea8107 100644 --- a/AsyncDisplayKit/ASCollectionView.mm +++ b/AsyncDisplayKit/ASCollectionView.mm @@ -643,7 +643,9 @@ static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell"; scrollView.contentOffset.y - ((targetContentOffset != NULL) ? targetContentOffset->y : 0) ); - [self handleBatchFetchScrollingToOffset:*targetContentOffset]; + if (targetContentOffset != NULL) { + [self handleBatchFetchScrollingToOffset:*targetContentOffset]; + } if ([_asyncDelegate respondsToSelector:@selector(scrollViewWillEndDragging:withVelocity:targetContentOffset:)]) { [_asyncDelegate scrollViewWillEndDragging:scrollView withVelocity:velocity targetContentOffset:targetContentOffset]; diff --git a/AsyncDisplayKit/ASTableView.mm b/AsyncDisplayKit/ASTableView.mm index 477c6ff4a3..99009d8eb9 100644 --- a/AsyncDisplayKit/ASTableView.mm +++ b/AsyncDisplayKit/ASTableView.mm @@ -637,8 +637,10 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell"; scrollView.contentOffset.x - ((targetContentOffset != NULL) ? targetContentOffset->x : 0), scrollView.contentOffset.y - ((targetContentOffset != NULL) ? targetContentOffset->y : 0) ); - - [self handleBatchFetchScrollingToOffset:*targetContentOffset]; + + if (targetContentOffset != NULL) { + [self handleBatchFetchScrollingToOffset:*targetContentOffset]; + } if ([_asyncDelegate respondsToSelector:@selector(scrollViewWillEndDragging:withVelocity:targetContentOffset:)]) { [_asyncDelegate scrollViewWillEndDragging:scrollView withVelocity:velocity targetContentOffset:targetContentOffset]; diff --git a/AsyncDisplayKit/Details/ASDataController.mm b/AsyncDisplayKit/Details/ASDataController.mm index a792eedc6d..32d62adac2 100644 --- a/AsyncDisplayKit/Details/ASDataController.mm +++ b/AsyncDisplayKit/Details/ASDataController.mm @@ -162,24 +162,37 @@ static void *kASSizingQueueContext = &kASSizingQueueContext; } NSUInteger nodeCount = nodes.count; - NSMutableArray *allocatedNodes = [NSMutableArray arrayWithCapacity:nodeCount]; + NSMutableArray *allocatedNodes = [NSMutableArray arrayWithCapacity:nodeCount]; dispatch_group_t layoutGroup = dispatch_group_create(); ASSizeRange *nodeBoundSizes = (ASSizeRange *)malloc(sizeof(ASSizeRange) * nodeCount); + for (NSUInteger j = 0; j < nodes.count && j < indexPaths.count; j += kASDataControllerSizingCountPerProcessor) { NSInteger batchCount = MIN(kASDataControllerSizingCountPerProcessor, indexPaths.count - j); + __block NSArray *subarray; + // Allocate nodes concurrently. dispatch_block_t allocationBlock = ^{ - for (NSUInteger k = j; k < j + batchCount; k++) { + __strong ASCellNode **allocatedNodeBuffer = (__strong ASCellNode **)calloc(batchCount, sizeof(ASCellNode *)); + dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); + dispatch_apply(batchCount, queue, ^(size_t i) { + unsigned long k = j + i; ASCellNodeBlock cellBlock = nodes[k]; ASCellNode *node = cellBlock(); ASDisplayNodeAssertNotNil(node, @"Node block created nil node"); - [allocatedNodes addObject:node]; + allocatedNodeBuffer[i] = node; if (!node.isNodeLoaded) { nodeBoundSizes[k] = [self constrainedSizeForNodeOfKind:kind atIndexPath:indexPaths[k]]; } + }); + subarray = [[NSArray alloc] initWithObjects:allocatedNodeBuffer count:batchCount]; + + // Nil out buffer indexes to allow arc to free the stored cells. + for (int i = 0; i < batchCount; i++) { + allocatedNodeBuffer[i] = nil; } + free(allocatedNodeBuffer); }; - + if (ASDisplayNodeThreadIsMain()) { dispatch_semaphore_t sema = dispatch_semaphore_create(0); dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ @@ -187,14 +200,16 @@ static void *kASSizingQueueContext = &kASSizingQueueContext; dispatch_semaphore_signal(sema); }); dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER); - [self layoutLoadedNodes:[allocatedNodes subarrayWithRange:NSMakeRange(j, batchCount)] ofKind:kind atIndexPaths:[indexPaths subarrayWithRange:NSMakeRange(j, batchCount)]]; + [self layoutLoadedNodes:subarray ofKind:kind atIndexPaths:[indexPaths subarrayWithRange:NSMakeRange(j, batchCount)]]; } else { allocationBlock(); [_mainSerialQueue performBlockOnMainThread:^{ - [self layoutLoadedNodes:[allocatedNodes subarrayWithRange:NSMakeRange(j, batchCount)] ofKind:kind atIndexPaths:[indexPaths subarrayWithRange:NSMakeRange(j, batchCount)]]; + [self layoutLoadedNodes:subarray ofKind:kind atIndexPaths:[indexPaths subarrayWithRange:NSMakeRange(j, batchCount)]]; }]; } + [allocatedNodes addObjectsFromArray:subarray]; + dispatch_group_async(layoutGroup, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ for (NSUInteger k = j; k < j + batchCount; k++) { ASCellNode *node = allocatedNodes[k]; diff --git a/AsyncDisplayKitTests/ASDisplayNodeTests.m b/AsyncDisplayKitTests/ASDisplayNodeTests.m index 9f34114231..455591cd1b 100644 --- a/AsyncDisplayKitTests/ASDisplayNodeTests.m +++ b/AsyncDisplayKitTests/ASDisplayNodeTests.m @@ -166,6 +166,7 @@ for (ASDisplayNode *n in @[ nodes ]) {\ } - (BOOL)resignFirstResponder { + [super resignFirstResponder]; if (self.isFirstResponder) { self.isFirstResponder = NO; return YES;