Working with UICollectionView

This guide provides details on how to work with UICollectionView and IGListKit.

Background

Early versions of IGListKit (2.x and prior) shipped with a subclass of UICollectionView called IGListCollectionView. The class contained no special functionality and was merely used to enforce compile-time restrictions to prevent users from calling certain methods directly on UICollectionView. Beginning with 3.0, IGListCollectionView was removed for a number of reasons.

For further discussion see #240 and #409.

Methods to avoid

One of the primary purposes of IGListKit is to perform optimal batch updates for UICollectionView. Thus, clients should never call any APIs on UICollectionView that involved reloading, inserting, deleting, or otherwise updating cells and index paths. Instead, use the APIs provided by IGListAdapter. You should also avoid setting the delegate and dataSource of the collection view, as this is also the responsibility of IGListAdapter.

Avoid calling the following methods:

- (void)performBatchUpdates:(void (^)(void))updates
                 completion:(void (^)(BOOL))completion;

- (void)reloadData;

- (void)reloadSections:(NSIndexSet *)sections;

- (void)insertSections:(NSIndexSet *)sections;

- (void)deleteSections:(NSIndexSet *)sections;

- (void)moveSection:(NSInteger)section toSection:(NSInteger)newSection;

- (void)insertItemsAtIndexPaths:(NSArray<NSIndexPath *> *)indexPaths;

- (void)reloadItemsAtIndexPaths:(NSArray<NSIndexPath *> *)indexPaths;

- (void)deleteItemsAtIndexPaths:(NSArray<NSIndexPath *> *)indexPaths;

- (void)moveItemAtIndexPath:(NSIndexPath *)indexPath toIndexPath:(NSIndexPath *)newIndexPath;

- (void)setDelegate:(id<UICollectionViewDelegate>)delegate;

- (void)setDataSource:(id<UICollectionViewDataSource>)dataSource;

- (void)setBackgroundView:(UIView *)backgroundView;

Performance

In iOS 10, a new cell prefetching API was introduced. At Instagram, enabling this feature substantially degraded scrolling performance. We recommend setting isPrefetchingEnabled to NO (false in Swift). Note that the default value is true.

You can set this globally using UIAppearance:

if ([[UICollectionView class] instancesRespondToSelector:@selector(setPrefetchingEnabled:)]) {
    [[UICollectionView appearance] setPrefetchingEnabled:NO];
}
if #available(iOS 10, *) {
    UICollectionView.appearance().isPrefetchingEnabled = false
}