diff --git a/AsyncDisplayKit/ASCollectionView.mm b/AsyncDisplayKit/ASCollectionView.mm index 5d31f49a4c..642a9fb825 100644 --- a/AsyncDisplayKit/ASCollectionView.mm +++ b/AsyncDisplayKit/ASCollectionView.mm @@ -1708,6 +1708,12 @@ static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell"; [_rangeController setNeedsUpdate]; [_rangeController updateIfNeeded]; } + + // When we aren't visible, we will only fetch up to the visible area. Now that we are visible, + // we will fetch visible area + leading screens, so we need to check. + if (visible) { + [self _checkForBatchFetching]; + } } #pragma mark ASCALayerExtendedDelegate diff --git a/AsyncDisplayKit/ASTableView.mm b/AsyncDisplayKit/ASTableView.mm index 1f0ec1d5c2..44da18d057 100644 --- a/AsyncDisplayKit/ASTableView.mm +++ b/AsyncDisplayKit/ASTableView.mm @@ -1725,6 +1725,12 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell"; [_rangeController setNeedsUpdate]; [_rangeController updateIfNeeded]; } + + // When we aren't visible, we will only fetch up to the visible area. Now that we are visible, + // we will fetch visible area + leading screens, so we need to check. + if (visible) { + [self _checkForBatchFetching]; + } } @end diff --git a/AsyncDisplayKit/Private/ASBatchFetching.h b/AsyncDisplayKit/Private/ASBatchFetching.h index a09fb898d3..7effc6bcb7 100644 --- a/AsyncDisplayKit/Private/ASBatchFetching.h +++ b/AsyncDisplayKit/Private/ASBatchFetching.h @@ -45,6 +45,7 @@ BOOL ASDisplayShouldFetchBatchForScrollView(UIScrollView_itemCounts = {0}; + [self _primitiveBatchFetchingFillTestAnimated:NO visible:NO controller:ctrl]; + XCTAssertGreaterThan([ctrl.collectionNode numberOfItemsInSection:0], 0); + [self _primitiveBatchFetchingFillTestAnimated:NO visible:YES controller:ctrl]; +} + +- (void)_primitiveBatchFetchingFillTestAnimated:(BOOL)animated visible:(BOOL)visible controller:(nullable ASCollectionViewTestController *)testController +{ + if (testController == nil) { + testController = [[ASCollectionViewTestController alloc] initWithNibName:nil bundle:nil]; + // Start with 1 empty section + testController.asyncDelegate->_itemCounts = {0}; + } + ASCollectionNode *cn = testController.collectionNode; + + UIWindow *window = nil; + UIView *view = nil; + if (visible) { + window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; + view = window; + } else { + view = cn.view; + view.frame = [UIScreen mainScreen].bounds; + } + + XCTestExpectation *expectation = [self expectationWithDescription:@"Completed all batch fetches"]; + __weak ASCollectionViewTestController *weakController = testController; + __block NSInteger batchFetchCount = 0; + testController.asyncDelegate.willBeginBatchFetch = ^(ASBatchContext *context) { + dispatch_async(dispatch_get_main_queue(), ^{ + NSInteger fetchIndex = batchFetchCount++; + + NSInteger itemCount = weakController.asyncDelegate->_itemCounts[0]; + weakController.asyncDelegate->_itemCounts[0] = (itemCount + 1); + if (animated) { + [cn insertItemsAtIndexPaths:@[ [NSIndexPath indexPathForItem:itemCount inSection:0] ]]; + } else { + [cn performBatchAnimated:NO updates:^{ + [cn insertItemsAtIndexPaths:@[ [NSIndexPath indexPathForItem:itemCount inSection:0] ]]; + } completion:nil]; + } + + [context completeBatchFetching:YES]; + + // If no more batch fetches have happened in 1 second, assume we're done. + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ + if (fetchIndex == batchFetchCount - 1) { + [expectation fulfill]; + } + }); + }); + }; + window.rootViewController = testController; + + [window makeKeyAndVisible]; + [view layoutIfNeeded]; + + [self waitForExpectationsWithTimeout:60 handler:nil]; + CGFloat contentHeight = cn.view.contentSize.height; + CGFloat requiredContentHeight; + CGFloat itemHeight = [cn.view layoutAttributesForItemAtIndexPath:[NSIndexPath indexPathForItem:0 inSection:0]].size.height; + if (visible) { + requiredContentHeight = CGRectGetMaxY(cn.bounds) + CGRectGetHeight(cn.bounds) * cn.view.leadingScreensForBatching; + } else { + requiredContentHeight = CGRectGetMaxY(cn.bounds); + } + XCTAssertGreaterThan(batchFetchCount, 2); + XCTAssertGreaterThanOrEqual(contentHeight, requiredContentHeight, @"Loaded too little content."); + XCTAssertLessThanOrEqual(contentHeight, requiredContentHeight + 2 * itemHeight, @"Loaded too much content."); +} + @end