Check for batch fetching on scroll (#2124)

## Summary

For collection views, we do not currently check for batch fetching on scroll. This appears to be a bug, as `scrollViewDidScroll:` does call `_checkForBatchFetching`, and [the commit that added it states it's trying to check on each scroll](https://github.com/TextureGroup/Texture/commit/df497b82c286771658a0ef0826945c716baaa783). Unfortunately, `_checkForBatchFetching` checks for `isTracking` and `isDragging` first and returns if either are `YES`. Since we're in a scroll, they are `YES`. So the call is effectively a no-op.

This bug has been around for 9 years and I'm unsure of the performance implications of turning the batch fetching check on for each scroll tick. Therefore, put the fix behind an experiment feature flag _and_ only call it on the first scroll tick for the scroll session, instead of every scroll tick. Finally, I moved the check after the delegate call, in case the delegate has logic in it to turn on or off the batch fetching.

## Test plan

Ran the app and manually tested batching getting called or not. Also ran `build.sh tests`.
This commit is contained in:
Andy Finnell
2025-05-22 13:07:34 -04:00
committed by GitHub
parent e894389a7e
commit be0b74b4e2
3 changed files with 19 additions and 2 deletions
+16 -1
View File
@@ -142,6 +142,12 @@ static NSString * const kReuseIdentifier = @"_ASCollectionReuseIdentifier";
*/
BOOL _hasEverCheckedForBatchFetchingDueToUpdate;
/**
* We want to check for batch fetching on scroll, but every tick would be too much. So check once at the
* beginning
*/
BOOL _hasCheckedForBatchFetchingOnScroll;
/**
* Set during beginInteractiveMovementForItemAtIndexPath and UIGestureRecognizerStateEnded
* (or UIGestureRecognizerStateFailed, UIGestureRecognizerStateCancelled.
@@ -1620,7 +1626,9 @@ static NSString * const kReuseIdentifier = @"_ASCollectionReuseIdentifier";
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
ASInterfaceState interfaceState = [self interfaceStateForRangeController:_rangeController];
if (ASInterfaceStateIncludesVisible(interfaceState)) {
if (ASInterfaceStateIncludesVisible(interfaceState) && !ASActivateExperimentalFeature(ASExperimentalCheckBatchFetchingOnScroll)) {
// The following call to _checkForBatchFetching is effectively a no-op, because during scrolling
// isDragging and isTracking are YES.
[self _checkForBatchFetching];
}
for (_ASCollectionViewCell *cell in _cellsForVisibilityUpdates) {
@@ -1630,6 +1638,11 @@ static NSString * const kReuseIdentifier = @"_ASCollectionReuseIdentifier";
if (_asyncDelegateFlags.scrollViewDidScroll) {
[_asyncDelegate scrollViewDidScroll:scrollView];
}
if (ASInterfaceStateIncludesVisible(interfaceState) && !_hasCheckedForBatchFetchingOnScroll && ASActivateExperimentalFeature(ASExperimentalCheckBatchFetchingOnScroll)) {
// Check after the delegate it give it a chance to turn on/off batch fetching
[self _beginBatchFetchingIfNeededWithContentOffset:self.contentOffset velocity:CGPointZero];
_hasCheckedForBatchFetchingOnScroll = YES;
}
}
- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset
@@ -1645,6 +1658,8 @@ static NSString * const kReuseIdentifier = @"_ASCollectionReuseIdentifier";
[self _beginBatchFetchingIfNeededWithContentOffset:*targetContentOffset velocity:velocity];
}
_hasCheckedForBatchFetchingOnScroll = NO; // reset once the scroll is done
if (_asyncDelegateFlags.scrollViewWillEndDragging) {
[_asyncDelegate scrollViewWillEndDragging:scrollView withVelocity:velocity targetContentOffset:(targetContentOffset ? : &contentOffset)];
}
+1
View File
@@ -34,6 +34,7 @@ typedef NS_OPTIONS(NSUInteger, ASExperimentalFeatures) {
ASExperimentalNoTextRendererCache = 1 << 13, // exp_no_text_renderer_cache
ASExperimentalLockTextRendererCache = 1 << 14, // exp_lock_text_renderer_cache
ASExperimentalHierarchyDisplayDidFinishIsRecursive = 1 << 15, // exp_hierarchy_display_did_finish_is_recursive
ASExperimentalCheckBatchFetchingOnScroll = 1 << 16, // exp_check_batch_fetching_on_scroll
ASExperimentalFeatureAll = 0xFFFFFFFF
};
+2 -1
View File
@@ -27,7 +27,8 @@ NSArray<NSString *> *ASExperimentalFeaturesGetNames(ASExperimentalFeatures flags
@"exp_range_update_on_changeset_update",
@"exp_no_text_renderer_cache",
@"exp_lock_text_renderer_cache",
@"exp_hierarchy_display_did_finish_is_recursive"]));
@"exp_hierarchy_display_did_finish_is_recursive",
@"exp_check_batch_fetching_on_scroll"]));
if (flags == ASExperimentalFeatureAll) {
return allNames;