mirror of
https://github.com/Instagram/IGListKit
synced 2026-05-24 09:48:21 +00:00
RFC: Diff in the background
Summary: Experimenting with a new change. We have observed instances of very large (3k+) lists stalling, even on modern devices. This is especially noticeable if the models being diffed are: - Immutable - `performUpdates:` often and models are alloc/init'd each time - The `isEqualToDiffableObject:` is sort of expensive (many `-[NSString isEqualToString:]` across thousands of models or something) Instead of just rolling this out, I plan on experimenting with results and seeing how much of a performance and stability boost we gain w/ this. Things to measure: - Scroll performance - CPU stalls - WatchDog kills on older devices Closes https://github.com/Instagram/IGListKit/pull/841 Reviewed By: amonshiz Differential Revision: D5364127 Pulled By: rnystrom fbshipit-source-id: 31d50d2e4b3c7c73584d6ec521a9047efd83f315
This commit is contained in:
parent
9f5bf3fb7e
commit
1d773aa533
2 changed files with 52 additions and 24 deletions
|
|
@ -18,6 +18,8 @@ NS_SWIFT_NAME(ListExperiment)
|
|||
typedef NS_OPTIONS (NSInteger, IGListExperiment) {
|
||||
/// Specifies no experiments.
|
||||
IGListExperimentNone = 1 << 1,
|
||||
/// Test updater diffing performed on a background queue.
|
||||
IGListExperimentBackgroundDiffing = 1 << 2,
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -176,9 +176,17 @@ static NSArray *objectsWithDuplicateIdentifiersRemoved(NSArray<id<IGListDiffable
|
|||
return;
|
||||
}
|
||||
|
||||
IGListIndexSetResult *result = IGListDiffExperiment(fromObjects, toObjects, IGListDiffEquality, self.experiments);
|
||||
// disables multiple performBatchUpdates: from happening at the same time
|
||||
[self beginPerformBatchUpdatesToObjects:toObjects];
|
||||
|
||||
void (^updateBlock)() = ^{
|
||||
const IGListExperiment experiments = self.experiments;
|
||||
|
||||
IGListIndexSetResult *(^performDiff)() = ^{
|
||||
return IGListDiffExperiment(fromObjects, toObjects, IGListDiffEquality, experiments);
|
||||
};
|
||||
|
||||
// block executed in the first param block of -[UICollectionView performBatchUpdates:completion:]
|
||||
void (^batchUpdatesBlock)(IGListIndexSetResult *result) = ^(IGListIndexSetResult *result){
|
||||
executeUpdateBlocks();
|
||||
|
||||
self.applyingUpdateData = [self flushCollectionView:collectionView
|
||||
|
|
@ -190,7 +198,8 @@ static NSArray *objectsWithDuplicateIdentifiersRemoved(NSArray<id<IGListDiffable
|
|||
[self performBatchUpdatesItemBlockApplied];
|
||||
};
|
||||
|
||||
void (^completionBlock)(BOOL) = ^(BOOL finished) {
|
||||
// block used as the second param of -[UICollectionView performBatchUpdates:completion:]
|
||||
void (^batchUpdatesCompletionBlock)(BOOL) = ^(BOOL finished) {
|
||||
executeCompletionBlocks(finished);
|
||||
|
||||
[delegate listAdapterUpdater:self didPerformBatchUpdates:(id)self.applyingUpdateData collectionView:collectionView];
|
||||
|
|
@ -200,28 +209,45 @@ static NSArray *objectsWithDuplicateIdentifiersRemoved(NSArray<id<IGListDiffable
|
|||
[self queueUpdateWithCollectionView:collectionView];
|
||||
};
|
||||
|
||||
// disables multiple performBatchUpdates: from happening at the same time
|
||||
[self beginPerformBatchUpdatesToObjects:toObjects];
|
||||
|
||||
@try {
|
||||
[delegate listAdapterUpdater:self willPerformBatchUpdatesWithCollectionView:collectionView];
|
||||
if (animated) {
|
||||
[collectionView performBatchUpdates:updateBlock completion:completionBlock];
|
||||
} else {
|
||||
[CATransaction begin];
|
||||
[CATransaction setDisableActions:YES];
|
||||
[collectionView performBatchUpdates:updateBlock completion:^(BOOL finished) {
|
||||
completionBlock(finished);
|
||||
[CATransaction commit];
|
||||
}];
|
||||
// block that executes the batch update and exception handling
|
||||
void (^performUpdate)(IGListIndexSetResult *) = ^(IGListIndexSetResult *result){
|
||||
@try {
|
||||
[delegate listAdapterUpdater:self willPerformBatchUpdatesWithCollectionView:collectionView];
|
||||
if (animated) {
|
||||
[collectionView performBatchUpdates:^{
|
||||
batchUpdatesBlock(result);
|
||||
} completion:batchUpdatesCompletionBlock];
|
||||
} else {
|
||||
[CATransaction begin];
|
||||
[CATransaction setDisableActions:YES];
|
||||
[collectionView performBatchUpdates:^{
|
||||
batchUpdatesBlock(result);
|
||||
} completion:^(BOOL finished) {
|
||||
batchUpdatesCompletionBlock(finished);
|
||||
[CATransaction commit];
|
||||
}];
|
||||
}
|
||||
} @catch (NSException *exception) {
|
||||
[delegate listAdapterUpdater:self
|
||||
willCrashWithException:exception
|
||||
fromObjects:fromObjects
|
||||
toObjects:toObjects
|
||||
updates:(id)self.applyingUpdateData];
|
||||
@throw exception;
|
||||
}
|
||||
} @catch (NSException *exception) {
|
||||
[delegate listAdapterUpdater:self
|
||||
willCrashWithException:exception
|
||||
fromObjects:fromObjects
|
||||
toObjects:toObjects
|
||||
updates:(id)self.applyingUpdateData];
|
||||
@throw exception;
|
||||
};
|
||||
|
||||
// temporary test to try out background diffing
|
||||
if (IGListExperimentEnabled(experiments, IGListExperimentBackgroundDiffing)) {
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||
IGListIndexSetResult *result = performDiff();
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
performUpdate(result);
|
||||
});
|
||||
});
|
||||
} else {
|
||||
IGListIndexSetResult *result = performDiff();
|
||||
performUpdate(result);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue