From 24ca09ee6caf0595fb701c007f700462dba3d1b5 Mon Sep 17 00:00:00 2001 From: Michael Schneider Date: Fri, 8 Apr 2016 19:42:14 -0700 Subject: [PATCH] Move most of the batch fetching logic to a central place for ASTableView and ASCollectionView usage --- AsyncDisplayKit/ASCollectionView.mm | 142 +++++++------- AsyncDisplayKit/ASTableView.mm | 219 +++++++++++----------- AsyncDisplayKit/Private/ASBatchFetching.h | 27 ++- AsyncDisplayKit/Private/ASBatchFetching.m | 30 +-- 4 files changed, 219 insertions(+), 199 deletions(-) diff --git a/AsyncDisplayKit/ASCollectionView.mm b/AsyncDisplayKit/ASCollectionView.mm index 784ef0b4a4..13e7c74362 100644 --- a/AsyncDisplayKit/ASCollectionView.mm +++ b/AsyncDisplayKit/ASCollectionView.mm @@ -91,7 +91,7 @@ static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell"; #pragma mark - #pragma mark ASCollectionView. -@interface ASCollectionView () { +@interface ASCollectionView () { ASCollectionViewProxy *_proxyDataSource; ASCollectionViewProxy *_proxyDelegate; @@ -605,8 +605,45 @@ static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell"; cellNode.scrollView = nil; } -#pragma mark - -#pragma mark Scroll Direction. + +- (void)scrollViewDidScroll:(UIScrollView *)scrollView +{ + // If a scroll happenes the current range mode needs to go to full + ASInterfaceState interfaceState = [self interfaceStateForRangeController:_rangeController]; + if (ASInterfaceStateIncludesVisible(interfaceState)) { + [_rangeController updateCurrentRangeWithMode:ASLayoutRangeModeFull]; + } + + for (_ASCollectionViewCell *collectionCell in _cellsForVisibilityUpdates) { + // Only nodes that respond to the selector are added to _cellsForVisibilityUpdates + [[collectionCell node] cellNodeVisibilityEvent:ASCellNodeVisibilityEventVisibleRectChanged + inScrollView:scrollView + withCellFrame:collectionCell.frame]; + } + if (_asyncDelegateImplementsScrollviewDidScroll) { + [_asyncDelegate scrollViewDidScroll:scrollView]; + } +} + +- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset +{ + _deceleratingVelocity = CGPointMake( + scrollView.contentOffset.x - ((targetContentOffset != NULL) ? targetContentOffset->x : 0), + scrollView.contentOffset.y - ((targetContentOffset != NULL) ? targetContentOffset->y : 0) + ); + + if (targetContentOffset != NULL) { + ASDisplayNodeAssert(_batchContext != nil, @"Batch context should exist"); + [self _beginBatchFetchingIfNeededWithScrollView:self forScrollDirection:[self scrollDirection] contentOffset:*targetContentOffset]; + } + + if ([_asyncDelegate respondsToSelector:@selector(scrollViewWillEndDragging:withVelocity:targetContentOffset:)]) { + [_asyncDelegate scrollViewWillEndDragging:scrollView withVelocity:velocity targetContentOffset:targetContentOffset]; + } +} + + +#pragma mark - Scroll Direction. - (ASScrollDirection)scrollDirection { @@ -700,58 +737,14 @@ static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell"; } -#pragma mark - -#pragma mark Batch Fetching +#pragma mark - Batch Fetching -- (void)_checkForBatchFetching +- (ASBatchContext *)batchContext { - // Dragging will be handled in scrollViewWillEndDragging:withVelocity:targetContentOffset: - if ([self isDragging] || [self isTracking] || ![self _shouldBatchFetch]) { - return; - } - - // Check if we should batch fetch - if (ASDisplayShouldFetchBatchForContext(_batchContext, [self scrollableDirections], self.bounds, self.contentSize, self.contentOffset, _leadingScreensForBatching)) { - [self _beginBatchFetching]; - } + return _batchContext; } -- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset -{ - _deceleratingVelocity = CGPointMake( - scrollView.contentOffset.x - ((targetContentOffset != NULL) ? targetContentOffset->x : 0), - scrollView.contentOffset.y - ((targetContentOffset != NULL) ? targetContentOffset->y : 0) - ); - - if (targetContentOffset != NULL) { - [self _handleBatchFetchScrollingToOffset:*targetContentOffset]; - } - - if ([_asyncDelegate respondsToSelector:@selector(scrollViewWillEndDragging:withVelocity:targetContentOffset:)]) { - [_asyncDelegate scrollViewWillEndDragging:scrollView withVelocity:velocity targetContentOffset:targetContentOffset]; - } -} - -- (void)scrollViewDidScroll:(UIScrollView *)scrollView -{ - // If a scroll happenes the current range mode needs to go to full - ASInterfaceState interfaceState = [self interfaceStateForRangeController:_rangeController]; - if (ASInterfaceStateIncludesVisible(interfaceState)) { - [_rangeController updateCurrentRangeWithMode:ASLayoutRangeModeFull]; - } - - for (_ASCollectionViewCell *collectionCell in _cellsForVisibilityUpdates) { - // Only nodes that respond to the selector are added to _cellsForVisibilityUpdates - [[collectionCell node] cellNodeVisibilityEvent:ASCellNodeVisibilityEventVisibleRectChanged - inScrollView:scrollView - withCellFrame:collectionCell.frame]; - } - if (_asyncDelegateImplementsScrollviewDidScroll) { - [_asyncDelegate scrollViewDidScroll:scrollView]; - } -} - -- (BOOL)_shouldBatchFetch +- (BOOL)canBatchFetch { // if the delegate does not respond to this method, there is no point in starting to fetch BOOL canFetch = [_asyncDelegate respondsToSelector:@selector(collectionView:willBeginBatchFetchWithContext:)]; @@ -762,25 +755,41 @@ static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell"; } } -- (void)_handleBatchFetchScrollingToOffset:(CGPoint)targetOffset +- (void)_scheduleCheckForBatchFetching { - ASDisplayNodeAssert(_batchContext != nil, @"Batch context should exist"); - - if (![self _shouldBatchFetch]) { + // Push this to the next runloop to be sure the UITableView has the right content size + dispatch_async(dispatch_get_main_queue(), ^{ + [self _checkForBatchFetching]; + }); +} + +- (void)_checkForBatchFetching +{ + // Dragging will be handled in scrollViewWillEndDragging:withVelocity:targetContentOffset: + if (self.isDragging || self.isTracking) { return; } - if (ASDisplayShouldFetchBatchForContext(_batchContext, [self scrollDirection], self.bounds, self.contentSize, targetOffset, _leadingScreensForBatching)) { + [self _beginBatchFetchingIfNeededWithScrollView:self forScrollDirection:[self scrollableDirections] contentOffset:self.contentOffset]; +} + +- (void)_beginBatchFetchingIfNeededWithScrollView:(UIScrollView *)scrollView forScrollDirection:(ASScrollDirection)scrollDirection contentOffset:(CGPoint)contentOffset +{ + if (ASDisplayShouldFetchBatchForScrollView(self, scrollDirection, contentOffset)) { [self _beginBatchFetching]; } } - (void)_beginBatchFetching { + NSLog(@"begin batch fetching"); + [_batchContext beginBatchFetching]; - dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ - [_asyncDelegate collectionView:self willBeginBatchFetchWithContext:_batchContext]; - }); + if ([_asyncDelegate respondsToSelector:@selector(collectionView:willBeginBatchFetchWithContext:)]) { + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + [_asyncDelegate collectionView:self willBeginBatchFetchWithContext:_batchContext]; + }); + } } @@ -972,7 +981,10 @@ static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell"; for (dispatch_block_t block in _batchUpdateBlocks) { block(); } - } completion:completion]; + } completion:^(BOOL finished){ + [self _scheduleCheckForBatchFetching]; + if (completion) { completion(finished); } + }]; }); [_batchUpdateBlocks removeAllObjects]; @@ -993,11 +1005,10 @@ static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell"; }]; } else { [_layoutFacilitator collectionViewWillEditCellsAtIndexPaths:indexPaths batched:NO]; - ASPerformBlockWithoutAnimationCompletion(YES, ^{ + [UIView performWithoutAnimation:^{ [super insertItemsAtIndexPaths:indexPaths]; - }, ^{ - - }); + [self _scheduleCheckForBatchFetching]; + }]; } } @@ -1017,6 +1028,7 @@ static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell"; [_layoutFacilitator collectionViewWillEditCellsAtIndexPaths:indexPaths batched:NO]; [UIView performWithoutAnimation:^{ [super deleteItemsAtIndexPaths:indexPaths]; + [self _scheduleCheckForBatchFetching]; }]; } } @@ -1037,6 +1049,7 @@ static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell"; [_layoutFacilitator collectionViewWillEditSectionsAtIndexSet:indexSet batched:NO]; [UIView performWithoutAnimation:^{ [super insertSections:indexSet]; + [self _scheduleCheckForBatchFetching]; }]; } } @@ -1057,6 +1070,7 @@ static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell"; [_layoutFacilitator collectionViewWillEditSectionsAtIndexSet:indexSet batched:NO]; [UIView performWithoutAnimation:^{ [super deleteSections:indexSet]; + [self _scheduleCheckForBatchFetching]; }]; } } diff --git a/AsyncDisplayKit/ASTableView.mm b/AsyncDisplayKit/ASTableView.mm index 18004ae84a..9be26beb23 100644 --- a/AsyncDisplayKit/ASTableView.mm +++ b/AsyncDisplayKit/ASTableView.mm @@ -88,9 +88,7 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell"; - (instancetype)_initWithTableView:(ASTableView *)tableView; @end -@interface ASTableView () +@interface ASTableView () { ASTableViewProxy *_proxyDataSource; ASTableViewProxy *_proxyDelegate; @@ -524,8 +522,8 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell"; } } -#pragma mark - -#pragma mark Intercepted selectors + +#pragma mark - Intercepted selectors - (void)setTableHeaderView:(UIView *)tableHeaderView { @@ -579,75 +577,6 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell"; return [_dataController numberOfRowsInSection:section]; } -- (ASScrollDirection)scrollDirection -{ - CGPoint scrollVelocity; - if (self.isTracking) { - scrollVelocity = [self.panGestureRecognizer velocityInView:self.superview]; - } else { - scrollVelocity = _deceleratingVelocity; - } - - ASScrollDirection scrollDirection = [self _scrollDirectionForVelocity:scrollVelocity]; - return ASScrollDirectionApplyTransform(scrollDirection, self.transform); -} - -- (ASScrollDirection)scrollableDirections -{ - ASScrollDirection scrollableDirection = ASScrollDirectionNone; - CGFloat totalContentWidth = self.contentSize.width + self.contentInset.left + self.contentInset.right; - CGFloat totalContentHeight = self.contentSize.height + self.contentInset.top + self.contentInset.bottom; - - if (self.alwaysBounceHorizontal || totalContentWidth > self.bounds.size.width) { // Can scroll horizontally. - scrollableDirection |= ASScrollDirectionHorizontalDirections; - } - if (self.alwaysBounceVertical || totalContentHeight > self.bounds.size.height) { // Can scroll vertically. - scrollableDirection |= ASScrollDirectionVerticalDirections; - } - return scrollableDirection; -} - -- (ASScrollDirection)_scrollDirectionForVelocity:(CGPoint)scrollVelocity -{ - ASScrollDirection direction = ASScrollDirectionNone; - ASScrollDirection scrollableDirections = [self scrollableDirections]; - - if (ASScrollDirectionContainsHorizontalDirection(scrollableDirections)) { // Can scroll horizontally. - if (scrollVelocity.x < 0.0) { - direction |= ASScrollDirectionRight; - } else if (scrollVelocity.x > 0.0) { - direction |= ASScrollDirectionLeft; - } - } - if (ASScrollDirectionContainsVerticalDirection(scrollableDirections)) { // Can scroll vertically. - if (scrollVelocity.y < 0.0) { - direction |= ASScrollDirectionDown; - } else if (scrollVelocity.y > 0.0) { - direction |= ASScrollDirectionUp; - } - } - - return direction; -} - -- (void)scrollViewDidScroll:(UIScrollView *)scrollView -{ - // If a scroll happenes the current range mode needs to go to full - ASInterfaceState interfaceState = [self interfaceStateForRangeController:_rangeController]; - if (ASInterfaceStateIncludesVisible(interfaceState)) { - [_rangeController updateCurrentRangeWithMode:ASLayoutRangeModeFull]; - } - - for (_ASTableViewCell *tableCell in _cellsForVisibilityUpdates) { - [[tableCell node] cellNodeVisibilityEvent:ASCellNodeVisibilityEventVisibleRectChanged - inScrollView:scrollView - withCellFrame:tableCell.frame]; - } - if (_asyncDelegateImplementsScrollviewDidScroll) { - [_asyncDelegate scrollViewDidScroll:scrollView]; - } -} - - (void)tableView:(UITableView *)tableView willDisplayCell:(_ASTableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath { _pendingVisibleIndexPath = indexPath; @@ -700,16 +629,22 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell"; } -#pragma mark - Batch Fetching - -- (void)_checkForBatchFetching +- (void)scrollViewDidScroll:(UIScrollView *)scrollView { - // Dragging will be handled in scrollViewWillEndDragging:withVelocity:targetContentOffset: - if ([self isDragging] || [self isTracking]) { - return; + // If a scroll happenes the current range mode needs to go to full + ASInterfaceState interfaceState = [self interfaceStateForRangeController:_rangeController]; + if (ASInterfaceStateIncludesVisible(interfaceState)) { + [_rangeController updateCurrentRangeWithMode:ASLayoutRangeModeFull]; } - [self _beginBatchFetchingIfNeededForScrollDirection:[self scrollableDirections] contentOffset:self.contentOffset]; + for (_ASTableViewCell *tableCell in _cellsForVisibilityUpdates) { + [[tableCell node] cellNodeVisibilityEvent:ASCellNodeVisibilityEventVisibleRectChanged + inScrollView:scrollView + withCellFrame:tableCell.frame]; + } + if (_asyncDelegateImplementsScrollviewDidScroll) { + [_asyncDelegate scrollViewDidScroll:scrollView]; + } } - (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset @@ -721,7 +656,7 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell"; if (targetContentOffset != NULL) { ASDisplayNodeAssert(_batchContext != nil, @"Batch context should exist"); - [self _beginBatchFetchingIfNeededForScrollDirection:[self scrollDirection] contentOffset:*targetContentOffset]; + [self _beginBatchFetchingIfNeededWithScrollView:self forScrollDirection:[self scrollDirection] contentOffset:*targetContentOffset]; } if ([_asyncDelegate respondsToSelector:@selector(scrollViewWillEndDragging:withVelocity:targetContentOffset:)]) { @@ -729,19 +664,69 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell"; } } -- (void)_beginBatchFetchingIfNeededForScrollDirection:(ASScrollDirection)scrollDirection contentOffset:(CGPoint)contentOffset + +#pragma mark - Scroll Direction + +- (ASScrollDirection)scrollDirection { - if (![self _shouldBatchFetch]) { - return; + CGPoint scrollVelocity; + if (self.isTracking) { + scrollVelocity = [self.panGestureRecognizer velocityInView:self.superview]; + } else { + scrollVelocity = _deceleratingVelocity; } - // Check if we should batch fetch - if (ASDisplayShouldFetchBatchForContext(_batchContext, [self scrollableDirections], self.bounds, self.contentSize, self.contentOffset, _leadingScreensForBatching)) { - [self _beginBatchFetching]; - } + ASScrollDirection scrollDirection = [self _scrollDirectionForVelocity:scrollVelocity]; + return ASScrollDirectionApplyTransform(scrollDirection, self.transform); } -- (BOOL)_shouldBatchFetch +- (ASScrollDirection)_scrollDirectionForVelocity:(CGPoint)scrollVelocity +{ + ASScrollDirection direction = ASScrollDirectionNone; + ASScrollDirection scrollableDirections = [self scrollableDirections]; + + if (ASScrollDirectionContainsHorizontalDirection(scrollableDirections)) { // Can scroll horizontally. + if (scrollVelocity.x < 0.0) { + direction |= ASScrollDirectionRight; + } else if (scrollVelocity.x > 0.0) { + direction |= ASScrollDirectionLeft; + } + } + if (ASScrollDirectionContainsVerticalDirection(scrollableDirections)) { // Can scroll vertically. + if (scrollVelocity.y < 0.0) { + direction |= ASScrollDirectionDown; + } else if (scrollVelocity.y > 0.0) { + direction |= ASScrollDirectionUp; + } + } + + return direction; +} + +- (ASScrollDirection)scrollableDirections +{ + ASScrollDirection scrollableDirection = ASScrollDirectionNone; + CGFloat totalContentWidth = self.contentSize.width + self.contentInset.left + self.contentInset.right; + CGFloat totalContentHeight = self.contentSize.height + self.contentInset.top + self.contentInset.bottom; + + if (self.alwaysBounceHorizontal || totalContentWidth > self.bounds.size.width) { // Can scroll horizontally. + scrollableDirection |= ASScrollDirectionHorizontalDirections; + } + if (self.alwaysBounceVertical || totalContentHeight > self.bounds.size.height) { // Can scroll vertically. + scrollableDirection |= ASScrollDirectionVerticalDirections; + } + return scrollableDirection; +} + + +#pragma mark - Batch Fetching + +- (ASBatchContext *)batchContext +{ + return _batchContext; +} + +- (BOOL)canBatchFetch { // if the delegate does not respond to this method, there is no point in starting to fetch BOOL canFetch = [_asyncDelegate respondsToSelector:@selector(tableView:willBeginBatchFetchWithContext:)]; @@ -752,12 +737,39 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell"; } } +- (void)_scheduleCheckForBatchFetching +{ + // Push this to the next runloop to be sure the UITableView has the right content size + dispatch_async(dispatch_get_main_queue(), ^{ + [self _checkForBatchFetching]; + }); +} + +- (void)_checkForBatchFetching +{ + // Dragging will be handled in scrollViewWillEndDragging:withVelocity:targetContentOffset: + if (self.isDragging || self.isTracking) { + return; + } + + [self _beginBatchFetchingIfNeededWithScrollView:self forScrollDirection:[self scrollableDirections] contentOffset:self.contentOffset]; +} + +- (void)_beginBatchFetchingIfNeededWithScrollView:(UIScrollView *)scrollView forScrollDirection:(ASScrollDirection)scrollDirection contentOffset:(CGPoint)contentOffset +{ + if (ASDisplayShouldFetchBatchForScrollView(self, scrollDirection, contentOffset)) { + [self _beginBatchFetching]; + } +} + - (void)_beginBatchFetching { [_batchContext beginBatchFetching]; - dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ - [_asyncDelegate tableView:self willBeginBatchFetchWithContext:_batchContext]; - }); + if ([_asyncDelegate respondsToSelector:@selector(tableView:willBeginBatchFetchWithContext:)]) { + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + [_asyncDelegate tableView:self willBeginBatchFetchWithContext:_batchContext]; + }); + } } #pragma mark - ASRangeControllerDataSource @@ -897,13 +909,9 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell"; } BOOL preventAnimation = animationOptions == UITableViewRowAnimationNone; - ASPerformBlockWithoutAnimation(preventAnimation, ^{ [super insertRowsAtIndexPaths:indexPaths withRowAnimation:(UITableViewRowAnimation)animationOptions]; - // Push this to the next runloop to be sure the UITableView has the right content size - dispatch_async(dispatch_get_main_queue(), ^{ - [self _checkForBatchFetching]; - }); + [self _scheduleCheckForBatchFetching]; }); if (_automaticallyAdjustsContentOffset) { @@ -923,10 +931,7 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell"; BOOL preventAnimation = animationOptions == UITableViewRowAnimationNone; ASPerformBlockWithoutAnimation(preventAnimation, ^{ [super deleteRowsAtIndexPaths:indexPaths withRowAnimation:(UITableViewRowAnimation)animationOptions]; - // Push this to the next runloop to be sure the UITableView has the right content size - dispatch_async(dispatch_get_main_queue(), ^{ - [self _checkForBatchFetching]; - }); + [self _scheduleCheckForBatchFetching]; }); if (_automaticallyAdjustsContentOffset) { @@ -947,10 +952,7 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell"; BOOL preventAnimation = animationOptions == UITableViewRowAnimationNone; ASPerformBlockWithoutAnimation(preventAnimation, ^{ [super insertSections:indexSet withRowAnimation:(UITableViewRowAnimation)animationOptions]; - // Push this to the next runloop to be sure the UITableView has the right content size - dispatch_async(dispatch_get_main_queue(), ^{ - [self _checkForBatchFetching]; - }); + [self _scheduleCheckForBatchFetching]; }); } @@ -966,10 +968,7 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell"; BOOL preventAnimation = animationOptions == UITableViewRowAnimationNone; ASPerformBlockWithoutAnimation(preventAnimation, ^{ [super deleteSections:indexSet withRowAnimation:(UITableViewRowAnimation)animationOptions]; - // Push this to the next runloop to be sure the UITableView has the right content size - dispatch_async(dispatch_get_main_queue(), ^{ - [self _checkForBatchFetching]; - }); + [self _scheduleCheckForBatchFetching]; }); } diff --git a/AsyncDisplayKit/Private/ASBatchFetching.h b/AsyncDisplayKit/Private/ASBatchFetching.h index 9aeea5ad26..6b0c1be595 100644 --- a/AsyncDisplayKit/Private/ASBatchFetching.h +++ b/AsyncDisplayKit/Private/ASBatchFetching.h @@ -10,27 +10,26 @@ #import "ASBatchContext.h" #import "ASScrollDirection.h" -#import "ASBaseDefines.h" ASDISPLAYNODE_EXTERN_C_BEGIN +@protocol ASBatchFetchingScrollView + +- (BOOL)canBatchFetch; +- (ASBatchContext *)batchContext; +- (CGFloat)leadingScreensForBatching; + +@end + /** @abstract Determine if batch fetching should begin based on the state of the parameters. - @param context The batch fetching context that contains knowledge about in-flight fetches. - @param scrollDirection The current scrolling direction of the scroll view. - @param bounds The bounds of the scrollview. - @param contentSize The content size of the scrollview. - @param targetOffset The offset that the scrollview will scroll to. - @param leadingScreens How many screens in the remaining distance will trigger batch fetching. - @return Whether or not the current state should proceed with batch fetching. @discussion This method is broken into a category for unit testing purposes and should be used with the ASTableView and * ASCollectionView batch fetching API. + @param context The scroll view that in-flight fetches are happening. + @param scrollDirection The current scrolling direction of the scroll view. + @param targetOffset The offset that the scrollview will scroll to. + @return Whether or not the current state should proceed with batch fetching. */ -extern BOOL ASDisplayShouldFetchBatchForContext(ASBatchContext *context, - ASScrollDirection scrollDirection, - CGRect bounds, - CGSize contentSize, - CGPoint targetOffset, - CGFloat leadingScreens); +BOOL ASDisplayShouldFetchBatchForScrollView(UIScrollView *scrollView, ASScrollDirection scrollDirection, CGPoint contentOffset); ASDISPLAYNODE_EXTERN_C_END diff --git a/AsyncDisplayKit/Private/ASBatchFetching.m b/AsyncDisplayKit/Private/ASBatchFetching.m index f25408e335..9158c30b84 100644 --- a/AsyncDisplayKit/Private/ASBatchFetching.m +++ b/AsyncDisplayKit/Private/ASBatchFetching.m @@ -8,23 +8,31 @@ #import "ASBatchFetching.h" -BOOL ASDisplayShouldFetchBatchForContext(ASBatchContext *context, - ASScrollDirection scrollDirection, - CGRect bounds, - CGSize contentSize, - CGPoint targetOffset, - CGFloat leadingScreens) { - // do not allow fetching if a batch is already in-flight and hasn't been completed or cancelled +BOOL ASDisplayShouldFetchBatchForScrollView(UIScrollView *scrollView, ASScrollDirection scrollDirection, CGPoint contentOffset) +{ + + // Don't fetch if the scroll view does not allow + if (![scrollView canBatchFetch]) { + return NO; + } + + // Check if we should batch fetch + ASBatchContext *context = scrollView.batchContext; + CGRect bounds = scrollView.bounds; + CGSize contentSize = scrollView.contentSize; + CGFloat leadingScreens = scrollView.leadingScreensForBatching; + + // Do not allow fetching if a batch is already in-flight and hasn't been completed or cancelled if ([context isFetching]) { return NO; } - // only Down and Right scrolls are currently supported (tail loading) + // Only Down and Right scrolls are currently supported (tail loading) if (!ASScrollDirectionContainsDown(scrollDirection) && !ASScrollDirectionContainsRight(scrollDirection)) { return NO; } - // no fetching for null states + // No fetching for null states if (leadingScreens <= 0.0 || CGRectEqualToRect(bounds, CGRectZero)) { return NO; } @@ -33,11 +41,11 @@ BOOL ASDisplayShouldFetchBatchForContext(ASBatchContext *context, if (ASScrollDirectionContainsDown(scrollDirection)) { viewLength = bounds.size.height; - offset = targetOffset.y; + offset = contentOffset.y; contentLength = contentSize.height; } else { // horizontal / right viewLength = bounds.size.width; - offset = targetOffset.x; + offset = contentOffset.x; contentLength = contentSize.width; }