mirror of
https://github.com/Instagram/IGListKit
synced 2026-05-22 00:38:42 +00:00
added experiment to make [IGListAdapter visibleSectionControllers] a bit faster
Summary: * Issue: [IGListAdapter visibleSectionControllers] calls [UICollectionViewLayout layoutAttributesForElementsInRect:] which can be expensive. And since visibleSectionControllers is called in scrollViewDidScroll, it can add up and take a toll on scroll performance. On an iPhone 7, it's in 2-10% of the main-thread samples (using Time Profiler). * Fix: IGListDisplayHandler conveniently keeps track of visible IGListSectionControllers, so let's just use that. Now, [IGListAdapter visibleSectionControllers] drops to ~0.3% of samples. Reviewed By: rnystrom Differential Revision: D6351474 fbshipit-source-id: 66914db95e08498927bfbceda4d2e9d58cbc7530
This commit is contained in:
parent
319928f697
commit
82a2a2ee18
6 changed files with 57 additions and 2 deletions
|
|
@ -9,11 +9,12 @@ The changelog for `IGListKit`. Also see the [releases](https://github.com/instag
|
|||
|
||||
- Added `-[IGListSectionController didHighlightItemAtIndex:]` and `-[IGListSectionController didUnhighlightItemAtIndex:]` APIs to support `UICollectionView` cell highlighting. [Kevin Delannoy](https://github.com/delannoyk) [(#933)](https://github.com/Instagram/IGListKit/pull/933)
|
||||
|
||||
|
||||
- Added a new listener API to be notified when `IGListAdapter` finishes updating. Add listeners via `-[IGListAdapter addUpdateListener:]` with objects conforming to the new `IGListAdapterUpdateListener` protocol. [Ryan Nystrom](https://github.com/rnystrom) [(tbd)](https://github.com/Instagram/IGListKit/pull/tbd)
|
||||
|
||||
- Updated project settings for iOS 11. [Ryan Nystrom](https://github.com/rnystrom) [(#942)](https://github.com/Instagram/IGListKit/pull/942)
|
||||
|
||||
- Added experiment to make `-[IGListAdapter visibleSectionControllers:]` a bit faster. [Maxime Ollivier](https://github.com/maxoll) (tbd)
|
||||
|
||||
### Fixes
|
||||
|
||||
- Duplicate objects for initial data source setup filtered out. [Mikhail Vashlyaev](https://github.com/yemodin) [(#993](https://github.com/Instagram/IGListKit/pull/993)
|
||||
|
|
|
|||
|
|
@ -22,6 +22,8 @@ typedef NS_OPTIONS (NSInteger, IGListExperiment) {
|
|||
IGListExperimentBackgroundDiffing = 1 << 2,
|
||||
/// Test fallback to reloadData when "too many" update operations.
|
||||
IGListExperimentReloadDataFallback = 1 << 3,
|
||||
/// Test a faster way to return visible section controllers.
|
||||
IGListExperimentFasterVisibleSectionController = 1 << 4,
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -484,6 +484,14 @@
|
|||
|
||||
- (NSArray<IGListSectionController *> *)visibleSectionControllers {
|
||||
IGAssertMainThread();
|
||||
if (IGListExperimentEnabled(self.experiments, IGListExperimentFasterVisibleSectionController)) {
|
||||
return [self visibleSectionControllersFromDisplayHandler];
|
||||
} else {
|
||||
return [self visibleSectionControllersFromLayoutAttributes];
|
||||
}
|
||||
}
|
||||
|
||||
- (NSArray<IGListSectionController *> *)visibleSectionControllersFromLayoutAttributes {
|
||||
NSMutableSet *visibleSectionControllers = [NSMutableSet new];
|
||||
NSArray<UICollectionViewLayoutAttributes *> *attributes =
|
||||
[self.collectionView.collectionViewLayout layoutAttributesForElementsInRect:self.collectionView.bounds];
|
||||
|
|
@ -497,6 +505,10 @@
|
|||
return [visibleSectionControllers allObjects];
|
||||
}
|
||||
|
||||
- (NSArray<IGListSectionController *> *)visibleSectionControllersFromDisplayHandler {
|
||||
return [[self.displayHandler visibleListSections] allObjects];
|
||||
}
|
||||
|
||||
- (NSArray *)visibleObjects {
|
||||
IGAssertMainThread();
|
||||
NSArray<UICollectionViewCell *> *visibleCells = [self.collectionView visibleCells];
|
||||
|
|
|
|||
|
|
@ -21,6 +21,11 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
IGLK_SUBCLASSING_RESTRICTED
|
||||
@interface IGListDisplayHandler : NSObject
|
||||
|
||||
/**
|
||||
Counted set of the currently visible section controllers.
|
||||
*/
|
||||
@property (nonatomic, strong, readonly) NSCountedSet<IGListSectionController *> *visibleListSections;
|
||||
|
||||
/**
|
||||
Tells the handler that a cell will be displayed in the IGListAdapter.
|
||||
|
||||
|
|
|
|||
|
|
@ -16,7 +16,6 @@
|
|||
|
||||
@interface IGListDisplayHandler ()
|
||||
|
||||
@property (nonatomic, strong) NSCountedSet *visibleListSections;
|
||||
@property (nonatomic, strong) NSMapTable *visibleViewObjectMap;
|
||||
|
||||
@end
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
#import <XCTest/XCTest.h>
|
||||
#import <OCMock/OCMock.h>
|
||||
|
||||
#import <IGListKit/IGListExperiments.h>
|
||||
#import <IGListKit/IGListKit.h>
|
||||
|
||||
#import "IGListAdapterInternal.h"
|
||||
|
|
@ -262,6 +263,22 @@
|
|||
XCTAssertTrue([visibleSectionControllers containsObject:[self.adapter sectionControllerForObject:@4]]);
|
||||
}
|
||||
|
||||
- (void)test_whenCellsExtendBeyondBounds_withFasterExperiment_thatVisibleSectionControllersAreLimited {
|
||||
// add experiment
|
||||
self.adapter.experiments |= IGListExperimentFasterVisibleSectionController;
|
||||
// # of items for each object == [item integerValue], so @2 has 2 items (cells)
|
||||
self.dataSource.objects = @[@1, @2, @3, @4, @5, @6, @7, @8, @9, @10, @11, @12];
|
||||
[self.adapter reloadDataWithCompletion:nil];
|
||||
XCTAssertEqual([self.collectionView numberOfSections], 12);
|
||||
NSArray *visibleSectionControllers = [self.adapter visibleSectionControllers];
|
||||
// UIWindow is 100x100, each cell is 100x10 so should have the following section/cell count: 1 + 2 + 3 + 4 = 10 (100 tall)
|
||||
XCTAssertEqual(visibleSectionControllers.count, 4);
|
||||
XCTAssertTrue([visibleSectionControllers containsObject:[self.adapter sectionControllerForObject:@1]]);
|
||||
XCTAssertTrue([visibleSectionControllers containsObject:[self.adapter sectionControllerForObject:@2]]);
|
||||
XCTAssertTrue([visibleSectionControllers containsObject:[self.adapter sectionControllerForObject:@3]]);
|
||||
XCTAssertTrue([visibleSectionControllers containsObject:[self.adapter sectionControllerForObject:@4]]);
|
||||
}
|
||||
|
||||
- (void) test_withEmptySectionPlusFooter_thatVisibleSectionControllersAreCorrect {
|
||||
self.dataSource.objects = @[@0];
|
||||
[self.adapter reloadDataWithCompletion:nil];
|
||||
|
|
@ -279,6 +296,25 @@
|
|||
XCTAssertTrue(visibleSectionControllers.firstObject.supplementaryViewSource == supplementarySource);
|
||||
}
|
||||
|
||||
- (void) test_withEmptySectionPlusFooter_withFasterExperiment_thatVisibleSectionControllersAreCorrect {
|
||||
// add experiment
|
||||
self.adapter.experiments |= IGListExperimentFasterVisibleSectionController;
|
||||
self.dataSource.objects = @[@0];
|
||||
[self.adapter reloadDataWithCompletion:nil];
|
||||
IGTestSupplementarySource *supplementarySource = [IGTestSupplementarySource new];
|
||||
supplementarySource.dequeueFromNib = YES;
|
||||
supplementarySource.collectionContext = self.adapter;
|
||||
supplementarySource.supportedElementKinds = @[UICollectionElementKindSectionFooter];
|
||||
IGListSectionController *controller = [self.adapter sectionControllerForObject:@0];
|
||||
controller.supplementaryViewSource = supplementarySource;
|
||||
supplementarySource.sectionController = controller;
|
||||
[self.adapter performUpdatesAnimated:NO completion:nil];
|
||||
NSArray<IGListSectionController *> *visibleSectionControllers = [self.adapter visibleSectionControllers];
|
||||
|
||||
XCTAssertTrue([visibleSectionControllers count] == 1);
|
||||
XCTAssertTrue(visibleSectionControllers.firstObject.supplementaryViewSource == supplementarySource);
|
||||
}
|
||||
|
||||
- (void)test_whenCellsExtendBeyondBounds_thatVisibleCellsExistForSectionControllers {
|
||||
self.dataSource.objects = @[@2, @3, @4, @5, @6];
|
||||
[self.adapter reloadDataWithCompletion:nil];
|
||||
|
|
|
|||
Loading…
Reference in a new issue