diff --git a/CHANGELOG.md b/CHANGELOG.md index 51b0b083..fc4d96ba 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,8 @@ The changelog for `IGListKit`. Also see the [releases](https://github.com/instag - 5x improvement to diffing performance when result is only inserts or deletes. [Ryan Nystrom](https://github.com/rnystrom) [(tbd)](tbd) +- Added `-[IGListCollectionContext dequeueReusableCellOfClass:withReuseIdentifier:forSectionController:atIndex:]` to allow for registering cells of the same class with different reuse identifiers. [Jeremy Lawrence](https://github.com/Ziewvater) (tbd) + ### Fixes - Copy objects when retrieving from datasource to prevent modification of models in binding section controller. [Kashish Goel](https://github.com/kashishgoel) [(#1109)](https://github.com/Instagram/IGListKit/pull/1109) diff --git a/Source/IGListAdapter.m b/Source/IGListAdapter.m index 199b472e..8b9a8171 100644 --- a/Source/IGListAdapter.m +++ b/Source/IGListAdapter.m @@ -929,15 +929,16 @@ } - (__kindof UICollectionViewCell *)dequeueReusableCellOfClass:(Class)cellClass - forSectionController:(IGListSectionController *)sectionController - atIndex:(NSInteger)index { + withReuseIdentifier:(NSString *)reuseIdentifier + forSectionController:(IGListSectionController *)sectionController + atIndex:(NSInteger)index { IGAssertMainThread(); IGParameterAssert(sectionController != nil); IGParameterAssert(cellClass != nil); IGParameterAssert(index >= 0); UICollectionView *collectionView = self.collectionView; - IGAssert(collectionView != nil, @"Dequeueing cell of class %@ from section controller %@ without a collection view at index %zi", NSStringFromClass(cellClass), sectionController, index); - NSString *identifier = IGListReusableViewIdentifier(cellClass, nil, nil); + IGAssert(collectionView != nil, @"Dequeueing cell of class %@ with reuseIdentifier %@ from section controller %@ without a collection view at index %zi", NSStringFromClass(cellClass), reuseIdentifier, sectionController, index); + NSString *identifier = IGListReusableViewIdentifier(cellClass, nil, nil, reuseIdentifier); NSIndexPath *indexPath = [self indexPathForSectionController:sectionController index:index usePreviousIfInUpdateBlock:NO]; if (![self.registeredCellClasses containsObject:cellClass]) { [self.registeredCellClasses addObject:cellClass]; @@ -946,6 +947,12 @@ return [collectionView dequeueReusableCellWithReuseIdentifier:identifier forIndexPath:indexPath]; } +- (__kindof UICollectionViewCell *)dequeueReusableCellOfClass:(Class)cellClass + forSectionController:(IGListSectionController *)sectionController + atIndex:(NSInteger)index { + return [self dequeueReusableCellOfClass:cellClass withReuseIdentifier:nil forSectionController:sectionController atIndex:index]; +} + - (__kindof UICollectionViewCell *)dequeueReusableCellFromStoryboardWithIdentifier:(NSString *)identifier forSectionController:(IGListSectionController *)sectionController atIndex:(NSInteger)index { @@ -988,7 +995,7 @@ IGParameterAssert(index >= 0); UICollectionView *collectionView = self.collectionView; IGAssert(collectionView != nil, @"Dequeueing cell of class %@ from section controller %@ without a collection view at index %zi with supplementary view %@", NSStringFromClass(viewClass), sectionController, index, elementKind); - NSString *identifier = IGListReusableViewIdentifier(viewClass, nil, elementKind); + NSString *identifier = IGListReusableViewIdentifier(viewClass, nil, elementKind, nil); NSIndexPath *indexPath = [self indexPathForSectionController:sectionController index:index usePreviousIfInUpdateBlock:NO]; if (![self.registeredSupplementaryViewIdentifiers containsObject:identifier]) { [self.registeredSupplementaryViewIdentifiers addObject:identifier]; diff --git a/Source/IGListCollectionContext.h b/Source/IGListCollectionContext.h index 0d790839..cdd33ec3 100644 --- a/Source/IGListCollectionContext.h +++ b/Source/IGListCollectionContext.h @@ -117,6 +117,23 @@ NS_SWIFT_NAME(ListCollectionContext) animated:(BOOL)animated scrollPosition:(UICollectionViewScrollPosition)scrollPosition; +/** + Dequeues a cell from the collection view reuse pool. + + @param cellClass The class of the cell you want to dequeue. + @param reuseIdentifier A reuse identifier for the specified cell. This parameter may be `nil`. + @param sectionController The section controller requesting this information. + @param index The index of the cell. + + @return A cell dequeued from the reuse pool or a newly created one. + + @note This method uses a string representation of the cell class as the identifier. + */ +- (__kindof UICollectionViewCell *)dequeueReusableCellOfClass:(Class)cellClass + withReuseIdentifier:(nullable NSString *)reuseIdentifier + forSectionController:(IGListSectionController *)sectionController + atIndex:(NSInteger)index; + /** Dequeues a cell from the collection view reuse pool. diff --git a/Source/IGListStackedSectionController.m b/Source/IGListStackedSectionController.m index bf18b343..75c1062c 100644 --- a/Source/IGListStackedSectionController.m +++ b/Source/IGListStackedSectionController.m @@ -296,14 +296,22 @@ static void * kStackedSectionControllerIndexKey = &kStackedSectionControllerInde } - (UICollectionViewCell *)dequeueReusableCellOfClass:(Class)cellClass + withReuseIdentifier:(NSString *)reuseIdentifier forSectionController:(IGListSectionController *)sectionController atIndex:(NSInteger)index { const NSInteger offsetIndex = [self relativeIndexForSectionController:sectionController fromLocalIndex:index]; return (UICollectionViewCell *_Nonnull)[self.collectionContext dequeueReusableCellOfClass:cellClass + withReuseIdentifier:reuseIdentifier forSectionController:self atIndex:offsetIndex]; } +- (UICollectionViewCell *)dequeueReusableCellOfClass:(Class)cellClass + forSectionController:(IGListSectionController *)sectionController + atIndex:(NSInteger)index { + return [self dequeueReusableCellOfClass:cellClass withReuseIdentifier:nil forSectionController:sectionController atIndex:index]; +} + - (UICollectionViewCell *)dequeueReusableCellWithNibName:(NSString *)nibName bundle:(NSBundle *)bundle forSectionController:(IGListSectionController *)sectionController diff --git a/Source/Internal/IGListAdapterInternal.h b/Source/Internal/IGListAdapterInternal.h index c13ae42d..3153ce0b 100644 --- a/Source/Internal/IGListAdapterInternal.h +++ b/Source/Internal/IGListAdapterInternal.h @@ -20,8 +20,8 @@ NS_ASSUME_NONNULL_BEGIN /// Generate a string representation of a reusable view class when registering with a UICollectionView. -NS_INLINE NSString *IGListReusableViewIdentifier(Class viewClass, NSString * _Nullable nibName, NSString * _Nullable kind) { - return [NSString stringWithFormat:@"%@%@%@", kind ?: @"", nibName ?: @"", NSStringFromClass(viewClass)]; +NS_INLINE NSString *IGListReusableViewIdentifier(Class viewClass, NSString * _Nullable nibName, NSString * _Nullable kind, NSString * _Nullable givenReuseIdentifier) { + return [NSString stringWithFormat:@"%@%@%@%@", kind ?: @"", nibName ?: @"", givenReuseIdentifier ?: @"", NSStringFromClass(viewClass)]; } @interface IGListAdapter () diff --git a/Tests/IGListAdapterTests.m b/Tests/IGListAdapterTests.m index 9ef53f1b..3c54af1d 100644 --- a/Tests/IGListAdapterTests.m +++ b/Tests/IGListAdapterTests.m @@ -139,18 +139,23 @@ } - (void)test_whenQueryingReusableIdentifier_thatIdentifierEqualsClassName { - NSString *identifier = IGListReusableViewIdentifier(UICollectionViewCell.class, nil, nil); + NSString *identifier = IGListReusableViewIdentifier(UICollectionViewCell.class, nil, nil, nil); XCTAssertEqualObjects(identifier, @"UICollectionViewCell"); } +- (void)test_whenQueryingReusableIdentifierWithGivenIdentifier_tahtIdentifierEqualsGivenIdentifierAndClassName { + NSString *identifier = IGListReusableViewIdentifier(UICollectionViewCell.class, nil, nil, @"MyCoolID"); + XCTAssertEqualObjects(identifier, @"MyCoolIDUICollectionViewCell"); +} + - (void)test_whenQueryingReusableIdentifier_thatIdentifierEqualsClassNameAndSupplimentaryKind { - NSString *identifier = IGListReusableViewIdentifier(UICollectionViewCell.class, nil, UICollectionElementKindSectionFooter); + NSString *identifier = IGListReusableViewIdentifier(UICollectionViewCell.class, nil, UICollectionElementKindSectionFooter, nil); XCTAssertEqualObjects(identifier, @"UICollectionElementKindSectionFooterUICollectionViewCell"); } - (void)test_whenQueryingReusableIdentifier_thatIdentifierEqualsClassNameAndNibName { NSString *nibName = @"IGNibName"; - NSString *identifier = IGListReusableViewIdentifier(UICollectionViewCell.class, nibName, nil); + NSString *identifier = IGListReusableViewIdentifier(UICollectionViewCell.class, nibName, nil, nil); XCTAssertEqualObjects(identifier, @"IGNibNameUICollectionViewCell"); }