mirror of
https://github.com/Instagram/IGListKit
synced 2026-05-23 09:18:29 +00:00
add IGListAdapterUpdaterDelegate calls to measure diffing performance
Summary: To prepare testing `Foundation` vs `IGListKit` diffing, lets measure how long it takes. Reviewed By: Haud Differential Revision: D22295546 fbshipit-source-id: 8023717f66ea68cbc24981272e8c134dd893274a
This commit is contained in:
parent
aa5b229ba2
commit
d5c7076063
3 changed files with 89 additions and 18 deletions
|
|
@ -17,6 +17,8 @@
|
|||
#import "IGListReloadIndexPath.h"
|
||||
#import "UICollectionView+IGListBatchUpdateData.h"
|
||||
|
||||
typedef void (^IGListAdapterUpdaterDiffResultBlock)(IGListIndexSetResult *);
|
||||
|
||||
@implementation IGListAdapterUpdater
|
||||
|
||||
- (instancetype)init {
|
||||
|
|
@ -112,6 +114,7 @@
|
|||
void (^objectTransitionBlock)(NSArray *) = [self.objectTransitionBlock copy];
|
||||
const BOOL animated = self.queuedUpdateIsAnimated;
|
||||
const BOOL allowsReloadingOnTooManyUpdates = self.allowsReloadingOnTooManyUpdates;
|
||||
const IGListExperiment experiments = self.experiments;
|
||||
IGListBatchUpdates *batchUpdates = self.batchUpdates;
|
||||
|
||||
// clean up all state so that new updates can be coalesced while the current update is in flight
|
||||
|
|
@ -197,12 +200,6 @@
|
|||
return;
|
||||
}
|
||||
|
||||
const IGListExperiment experiments = self.experiments;
|
||||
|
||||
IGListIndexSetResult *(^performDiff)(void) = ^{
|
||||
return IGListDiffExperiment(fromObjects, toObjects, IGListDiffEquality, experiments);
|
||||
};
|
||||
|
||||
// block executed in the first param block of -[UICollectionView performBatchUpdates:completion:]
|
||||
void (^batchUpdatesBlock)(IGListIndexSetResult *result) = ^(IGListIndexSetResult *result){
|
||||
executeUpdateBlocks();
|
||||
|
|
@ -230,7 +227,7 @@
|
|||
experiments,
|
||||
self.movesAsDeletesInserts,
|
||||
self.preferItemReloadsForSectionReloads);
|
||||
}
|
||||
}
|
||||
|
||||
[self _cleanStateAfterUpdates];
|
||||
[self _performBatchUpdatesItemBlockApplied];
|
||||
|
|
@ -306,17 +303,12 @@ willPerformBatchUpdatesWithCollectionView:collectionView
|
|||
}
|
||||
};
|
||||
|
||||
if (IGListExperimentEnabled(experiments, IGListExperimentBackgroundDiffing)) {
|
||||
dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0), ^{
|
||||
IGListIndexSetResult *result = performDiff();
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
tryToPerformUpdate(result);
|
||||
});
|
||||
});
|
||||
} else {
|
||||
IGListIndexSetResult *result = performDiff();
|
||||
const BOOL onBackgroundThread = IGListExperimentEnabled(experiments, IGListExperimentBackgroundDiffing);
|
||||
[delegate listAdapterUpdater:self willDiffFromObjects:fromObjects toObjects:toObjects];
|
||||
IGListAdapterUpdaterPerformDiffing(fromObjects, toObjects, IGListDiffEquality, onBackgroundThread, experiments, ^(IGListIndexSetResult *result){
|
||||
[delegate listAdapterUpdater:self didDiffWithResults:result onBackgroundThread:onBackgroundThread];
|
||||
tryToPerformUpdate(result);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
- (void)_beginPerformBatchUpdatesToObjects:(NSArray *)toObjects {
|
||||
|
|
@ -374,7 +366,6 @@ willPerformBatchUpdatesWithCollectionView:collectionView
|
|||
});
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - IGListUpdatingDelegate
|
||||
|
||||
static BOOL IGListIsEqual(const void *a, const void *b, NSUInteger (*size)(const void *item)) {
|
||||
|
|
@ -575,5 +566,25 @@ static NSUInteger IGListIdentifierHash(const void *item, NSUInteger (*size)(cons
|
|||
}
|
||||
}
|
||||
|
||||
#pragma mark - Diffing
|
||||
|
||||
static void IGListAdapterUpdaterPerformDiffing(NSArray<id<IGListDiffable>> *_Nullable oldArray,
|
||||
NSArray<id<IGListDiffable>> *_Nullable newArray,
|
||||
IGListDiffOption option,
|
||||
IGListExperiment experiments,
|
||||
BOOL onBackgroundThread,
|
||||
IGListAdapterUpdaterDiffResultBlock completion) {
|
||||
if (onBackgroundThread) {
|
||||
dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0), ^{
|
||||
IGListIndexSetResult *result = IGListDiffExperiment(oldArray, newArray, option, experiments);
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
completion(result);
|
||||
});
|
||||
});
|
||||
} else {
|
||||
IGListIndexSetResult *result = IGListDiffExperiment(oldArray, newArray, option, experiments);
|
||||
completion(result);
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
|||
|
|
@ -21,6 +21,28 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
NS_SWIFT_NAME(ListAdapterUpdaterDelegate)
|
||||
@protocol IGListAdapterUpdaterDelegate <NSObject>
|
||||
|
||||
/**
|
||||
Notifies the delegate that the updater is about to beging diffing.
|
||||
|
||||
@param listAdapterUpdater The adapter updater owning the transition.
|
||||
@param fromObjects The items transitioned from in the batch updates, if any.
|
||||
@param toObjects The items transitioned to in the batch updates, if any.
|
||||
*/
|
||||
- (void)listAdapterUpdater:(IGListAdapterUpdater *)listAdapterUpdater
|
||||
willDiffFromObjects:(nullable NSArray <id<IGListDiffable>> *)fromObjects
|
||||
toObjects:(nullable NSArray <id<IGListDiffable>> *)toObjects;
|
||||
|
||||
/**
|
||||
Notifies the delegate that the updater finished diffing.
|
||||
|
||||
@param listAdapterUpdater The adapter updater owning the transition.
|
||||
@param listIndexSetResults The diffing result of indices to be inserted/removed/updated/moved/etc.
|
||||
@param onBackgroundThread Was the diffing performed on a background thread
|
||||
*/
|
||||
- (void)listAdapterUpdater:(IGListAdapterUpdater *)listAdapterUpdater
|
||||
didDiffWithResults:(nullable IGListIndexSetResult *)listIndexSetResults
|
||||
onBackgroundThread:(BOOL)onBackgroundThread;
|
||||
|
||||
/**
|
||||
Notifies the delegate that the updater will call `-[UICollectionView performBatchUpdates:completion:]`.
|
||||
|
||||
|
|
|
|||
|
|
@ -814,6 +814,44 @@
|
|||
[self waitForExpectationsWithTimeout:30 handler:nil];
|
||||
}
|
||||
|
||||
- (void)test_whenPerformingUpdate_thatCallsDiffingDelegate {
|
||||
self.updater.experiments |= IGListExperimentBackgroundDiffing;
|
||||
|
||||
NSArray *from = @[
|
||||
[IGSectionObject sectionWithObjects:@[] identifier:@"0"]
|
||||
];
|
||||
NSArray *to = @[
|
||||
[IGSectionObject sectionWithObjects:@[] identifier:@"0"],
|
||||
[IGSectionObject sectionWithObjects:@[] identifier:@"1"]
|
||||
];
|
||||
IGListToObjectBlock toBlock = ^NSArray *{
|
||||
return to;
|
||||
};
|
||||
|
||||
self.dataSource.sections = from;
|
||||
[self.updater performReloadDataWithCollectionViewBlock:[self collectionViewBlock]];
|
||||
|
||||
id mockDelegate = [OCMockObject niceMockForProtocol:@protocol(IGListAdapterUpdaterDelegate)];
|
||||
self.updater.delegate = mockDelegate;
|
||||
[mockDelegate setExpectationOrderMatters:YES];
|
||||
[[mockDelegate expect] listAdapterUpdater:self.updater willDiffFromObjects:from toObjects:to];
|
||||
[[mockDelegate expect] listAdapterUpdater:self.updater didDiffWithResults:[OCMArg checkWithBlock:^BOOL(IGListIndexSetResult *result) {
|
||||
return [result.inserts isEqualToIndexSet:[NSIndexSet indexSetWithIndex:1]]
|
||||
&& result.deletes.count == 0
|
||||
&& result.updates.count == 0
|
||||
&& result.moves.count == 0;
|
||||
}] onBackgroundThread:YES];
|
||||
|
||||
XCTestExpectation *expectation = genExpectation;
|
||||
|
||||
[self.updater performUpdateWithCollectionViewBlock:[self collectionViewBlock] fromObjects:from toObjectsBlock:toBlock animated:NO objectTransitionBlock:self.updateBlock completion:^(BOOL finished) {
|
||||
[expectation fulfill];
|
||||
}];
|
||||
waitExpectation;
|
||||
[mockDelegate verify];
|
||||
}
|
||||
|
||||
|
||||
# pragma mark - preferItemReloadsFroSectionReloads
|
||||
|
||||
- (void)test_whenReloadIsCalledWithSameItemCount_andPreferItemReload_updateIndexPathsHappen {
|
||||
|
|
|
|||
Loading…
Reference in a new issue