Add experiment for reloadData on large changesets

Summary:
Preparing another perf test. I noticed in some surfaces that have **massive** updates (8k+ inserts/deletes) that perf can be pretty awful. This is all due to internals of `UICollectionView` trying to create cells and animate a huge blob of changes. Instead, I'm picking a sensible (is it?) default to just skip batch updates and do `reloadData` instead.

Unit tests caught that the `layoutIfNeeded` is required to immediately configure cells.

Depends on D5392713

Reviewed By: jeremycohen

Differential Revision: D5392882

fbshipit-source-id: e429ddb7bca7400908898ebc6f097a489211b03d
This commit is contained in:
Ryan Nystrom 2017-07-12 12:40:18 -07:00 committed by Facebook Github Bot
parent dfc6b687a8
commit 61c1524bb0
2 changed files with 35 additions and 6 deletions

View file

@ -15,6 +15,7 @@
#import <IGListKit/IGListDiff.h>
#import "UICollectionView+IGListBatchUpdateData.h"
#import "IGListIndexSetResultInternal.h"
#import "IGListMoveIndexPathInternal.h"
#import "IGListReloadIndexPath.h"
@ -167,16 +168,21 @@ static NSArray *objectsWithDuplicateIdentifiersRemoved(NSArray<id<IGListDiffable
}
};
void (^reloadDataFallback)() = ^{
executeUpdateBlocks();
[self cleanStateAfterUpdates];
[self performBatchUpdatesItemBlockApplied];
[collectionView reloadData];
[collectionView layoutIfNeeded];
executeCompletionBlocks(YES);
};
// if the collection view isn't in a visible window, skip diffing and batch updating. execute all transition blocks,
// reload data, execute completion blocks, and get outta here
const BOOL iOS83OrLater = (NSFoundationVersionNumber >= NSFoundationVersionNumber_iOS_8_3);
if (iOS83OrLater && self.allowsBackgroundReloading && collectionView.window == nil) {
[self beginPerformBatchUpdatesToObjects:toObjects];
executeUpdateBlocks();
[self cleanStateAfterUpdates];
[self performBatchUpdatesItemBlockApplied];
[collectionView reloadData];
executeCompletionBlocks(YES);
reloadDataFallback();
return;
}
@ -217,7 +223,9 @@ static NSArray *objectsWithDuplicateIdentifiersRemoved(NSArray<id<IGListDiffable
void (^performUpdate)(IGListIndexSetResult *) = ^(IGListIndexSetResult *result){
@try {
[delegate listAdapterUpdater:self willPerformBatchUpdatesWithCollectionView:collectionView];
if (animated) {
if (result.changeCount > 100 && IGListExperimentEnabled(experiments, IGListExperimentReloadDataFallback)) {
reloadDataFallback();
} else if (animated) {
[collectionView performBatchUpdates:^{
batchUpdatesBlock(result);
} completion:batchUpdatesCompletionBlock];

View file

@ -1521,4 +1521,25 @@
[self waitForExpectationsWithTimeout:30 handler:nil];
}
- (void)test_whenMassiveUpdate_thatUpdateApplied {
// init empty
[self setupWithObjects:@[]];
((IGListAdapterUpdater *)self.updater).experiments = IGListExperimentReloadDataFallback;
NSMutableArray *objects = [NSMutableArray new];
for (NSInteger i = 0; i < 3000; i++) {
[objects addObject:genTestObject(@(i + 1), @4)];
}
self.dataSource.objects = objects;
XCTestExpectation *expectation = genExpectation;
[self.adapter performUpdatesAnimated:YES completion:^(BOOL finished) {
XCTAssertEqual([self.collectionView numberOfSections], 3000);
[expectation fulfill];
}];
[self waitForExpectationsWithTimeout:30 handler:nil];
}
@end