From 106054c1816e986cd03febb0752d854dd637f61d Mon Sep 17 00:00:00 2001 From: Adlai Holler Date: Thu, 9 Feb 2017 11:25:11 -0800 Subject: [PATCH] Add -[IGListAdapter sectionControllerForSection:] Summary: Before the diff, you can lookup the object for a given section, and then lookup the section controller for that object, but this seems like a pretty valuable/common operation. Closes https://github.com/Instagram/IGListKit/pull/477 Differential Revision: D4537479 Pulled By: rnystrom fbshipit-source-id: ad47a243f0bb0fc72a362863dff2f00b0b640fab --- CHANGELOG.md | 2 ++ Source/IGListAdapter.h | 9 +++++++++ Source/IGListAdapter.m | 26 ++++++++++++++++---------- Tests/IGListAdapterTests.m | 9 +++++++++ 4 files changed, 36 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8f1e3ed6..e2921253 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -38,6 +38,8 @@ This release closes the [2.2.0 milestone](https://github.com/Instagram/IGListKit - Added `-[IGListAdapter visibleCellsForObject:]` API. [Sherlouk](https://github.com/Sherlouk) [(#442)](https://github.com/Instagram/IGListKit/pull/442) +- Added `-[IGListAdapter sectionControllerForSection:]` API. [Adlai-Holler](https://github.com/Adlai-Holler) [(#477)](https://github.com/Instagram/IGListKit/pull/477) + ### Fixes - Fix bug where emptyView's hidden status is not updated after the number of items is changed with `insertInSectionController:atIndexes:` or related methods. [Peter Edmonston](https://github.com/edmonston) [(#395)](https://github.com/Instagram/IGListKit/pull/395) diff --git a/Source/IGListAdapter.h b/Source/IGListAdapter.h index 7ed5422b..6d463661 100644 --- a/Source/IGListAdapter.h +++ b/Source/IGListAdapter.h @@ -126,6 +126,15 @@ IGLK_SUBCLASSING_RESTRICTED */ - (void)reloadObjects:(NSArray *)objects; +/** + Query the section controller at a given section index. Constant time lookup. + + @param section A section in the list. + + @return An section controller or `nil` if the section does not exist. + */ +- (nullable IGListSectionController *)sectionControllerForSection:(NSInteger)section; + /** Query the section index of a list. Constant time lookup. diff --git a/Source/IGListAdapter.m b/Source/IGListAdapter.m index 54d5fd90..2b07dd24 100644 --- a/Source/IGListAdapter.m +++ b/Source/IGListAdapter.m @@ -339,6 +339,12 @@ #pragma mark - List Items & Sections +- (nullable IGListSectionController *)sectionControllerForSection:(NSInteger)section { + IGAssertMainThread(); + + return [self.sectionMap sectionControllerForSection:section]; +} + - (NSInteger)sectionForSectionController:(IGListSectionController *)sectionController { IGAssertMainThread(); IGParameterAssert(sectionController != nil); @@ -381,7 +387,7 @@ } - (id)supplementaryViewSourceAtIndexPath:(NSIndexPath *)indexPath { - IGListSectionController *sectionController = [self.sectionMap sectionControllerForSection:indexPath.section]; + IGListSectionController *sectionController = [self sectionControllerForSection:indexPath.section]; return [sectionController supplementaryViewSource]; } @@ -443,7 +449,7 @@ - (CGSize)sizeForItemAtIndexPath:(NSIndexPath *)indexPath { IGAssertMainThread(); - IGListSectionController *sectionController = [self.sectionMap sectionControllerForSection:indexPath.section]; + IGListSectionController *sectionController = [self sectionControllerForSection:indexPath.section]; return [sectionController sizeForItemAtIndex:indexPath.item]; } @@ -641,7 +647,7 @@ } - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section { - IGListSectionController * sectionController = [self.sectionMap sectionControllerForSection:section]; + IGListSectionController * sectionController = [self sectionControllerForSection:section]; IGAssert(sectionController != nil, @"Nil section controller for section %zi for item %@. Check your -diffIdentifier and -isEqual: implementations.", section, [self.sectionMap objectForSection:section]); const NSInteger numberOfItems = [sectionController numberOfItems]; @@ -650,7 +656,7 @@ } - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath { - IGListSectionController *sectionController = [self.sectionMap sectionControllerForSection:indexPath.section]; + IGListSectionController *sectionController = [self sectionControllerForSection:indexPath.section]; // flag that a cell is being dequeued in case it tries to access a cell in the process _isDequeuingCell = YES; @@ -666,7 +672,7 @@ } - (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath { - IGListSectionController *sectionController = [self.sectionMap sectionControllerForSection:indexPath.section]; + IGListSectionController *sectionController = [self sectionControllerForSection:indexPath.section]; id supplementarySource = [sectionController supplementaryViewSource]; UICollectionReusableView *view = [supplementarySource viewForSupplementaryElementOfKind:kind atIndex:indexPath.item]; IGAssert(view != nil, @"Returned a nil supplementary view at indexPath <%@> from section controller: <%@>, supplementary source: <%@>", indexPath, sectionController, supplementarySource); @@ -683,7 +689,7 @@ [collectionViewDelegate collectionView:collectionView didSelectItemAtIndexPath:indexPath]; } - IGListSectionController * sectionController = [self.sectionMap sectionControllerForSection:indexPath.section]; + IGListSectionController * sectionController = [self sectionControllerForSection:indexPath.section]; [sectionController didSelectItemAtIndex:indexPath.item]; } @@ -698,7 +704,7 @@ // if the section controller relationship was destroyed, reconnect it // this happens with iOS 10 UICollectionView display range changes if (sectionController == nil) { - sectionController = [self.sectionMap sectionControllerForSection:indexPath.section]; + sectionController = [self sectionControllerForSection:indexPath.section]; [self mapCell:cell toSectionController:sectionController]; } @@ -1054,17 +1060,17 @@ - (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout insetForSectionAtIndex:(NSInteger)section { IGAssert(![self.collectionViewDelegate respondsToSelector:_cmd], @"IGListAdapter is consuming method also implemented by the collectionViewDelegate: %@", NSStringFromSelector(_cmd)); - return [[self.sectionMap sectionControllerForSection:section] inset]; + return [[self sectionControllerForSection:section] inset]; } - (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section { IGAssert(![self.collectionViewDelegate respondsToSelector:_cmd], @"IGListAdapter is consuming method also implemented by the collectionViewDelegate: %@", NSStringFromSelector(_cmd)); - return [[self.sectionMap sectionControllerForSection:section] minimumLineSpacing]; + return [[self sectionControllerForSection:section] minimumLineSpacing]; } - (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section { IGAssert(![self.collectionViewDelegate respondsToSelector:_cmd], @"IGListAdapter is consuming method also implemented by the collectionViewDelegate: %@", NSStringFromSelector(_cmd)); - return [[self.sectionMap sectionControllerForSection:section] minimumInteritemSpacing]; + return [[self sectionControllerForSection:section] minimumInteritemSpacing]; } - (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout referenceSizeForHeaderInSection:(NSInteger)section { diff --git a/Tests/IGListAdapterTests.m b/Tests/IGListAdapterTests.m index 5e79ad25..0d2ab148 100644 --- a/Tests/IGListAdapterTests.m +++ b/Tests/IGListAdapterTests.m @@ -783,6 +783,15 @@ XCTAssertEqual(CGPointEqualToPoint(point, p), YES); \ XCTAssertEqual([self.adapter sectionForObject:@3], NSNotFound); } +- (void)test_whenQueryingSectionControllerForSection_thatControllerReturned { + self.dataSource.objects = @[@0, @1, @2]; + [self.adapter reloadDataWithCompletion:nil]; + + XCTAssertEqual([self.adapter sectionControllerForSection:0], [self.adapter sectionControllerForObject:@0]); + XCTAssertEqual([self.adapter sectionControllerForSection:1], [self.adapter sectionControllerForObject:@1]); + XCTAssertEqual([self.adapter sectionControllerForSection:2], [self.adapter sectionControllerForObject:@2]); +} + - (void)test_whenReloadingData_withNoDataSource_thatCompletionCalledWithNO { self.dataSource.objects = @[@1]; IGListAdapter *adapter = [[IGListAdapter alloc] initWithUpdater:[IGListReloadDataUpdater new]