diff --git a/AsyncDisplayKit/ASCollectionNode+Beta.h b/AsyncDisplayKit/ASCollectionNode+Beta.h index 11ea3ac2..e05e740b 100644 --- a/AsyncDisplayKit/ASCollectionNode+Beta.h +++ b/AsyncDisplayKit/ASCollectionNode+Beta.h @@ -14,6 +14,8 @@ NS_ASSUME_NONNULL_BEGIN @interface ASCollectionNode (Beta) - (instancetype)initWithFrame:(CGRect)frame collectionViewLayout:(UICollectionViewLayout *)layout layoutFacilitator:(nullable id)layoutFacilitator; +- (void)beginUpdates; +- (void)endUpdatesAnimated:(BOOL)animated; @end diff --git a/AsyncDisplayKit/ASCollectionNode.mm b/AsyncDisplayKit/ASCollectionNode.mm index 5bed1a1b..3d5c3d92 100644 --- a/AsyncDisplayKit/ASCollectionNode.mm +++ b/AsyncDisplayKit/ASCollectionNode.mm @@ -187,6 +187,16 @@ [self.view clearFetchedData]; } +- (void)beginUpdates +{ + [self.view.dataController beginUpdates]; +} + +- (void)endUpdatesAnimated:(BOOL)animated +{ + [self.view.dataController endUpdatesAnimated:animated completion:nil]; +} + #pragma mark - ASCollectionView Forwards - (ASRangeTuningParameters)tuningParametersForRangeType:(ASLayoutRangeType)rangeType diff --git a/AsyncDisplayKit/ASCollectionView.mm b/AsyncDisplayKit/ASCollectionView.mm index 2b588d08..e8ae9085 100644 --- a/AsyncDisplayKit/ASCollectionView.mm +++ b/AsyncDisplayKit/ASCollectionView.mm @@ -396,6 +396,11 @@ static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell"; #pragma mark Assertions. +- (ASDataController *)dataController +{ + return _dataController; +} + - (void)performBatchAnimated:(BOOL)animated updates:(void (^)())updates completion:(void (^)(BOOL))completion { ASDisplayNodeAssertMainThread(); @@ -851,6 +856,7 @@ static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell"; } ASPerformBlockWithoutAnimation(!animated, ^{ + [_layoutFacilitator collectionViewWillPerformBatchUpdates]; [super performBatchUpdates:^{ for (dispatch_block_t block in _batchUpdateBlocks) { block(); @@ -865,16 +871,17 @@ static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell"; - (void)rangeController:(ASRangeController *)rangeController didInsertNodes:(NSArray *)nodes atIndexPaths:(NSArray *)indexPaths withAnimationOptions:(ASDataControllerAnimationOptions)animationOptions { ASDisplayNodeAssertMainThread(); - [_layoutFacilitator collectionViewEditingCellsAtIndexPaths:indexPaths]; if (!self.asyncDataSource || _superIsPendingDataLoad) { return; // if the asyncDataSource has become invalid while we are processing, ignore this request to avoid crashes } if (_performingBatchUpdates) { + [_layoutFacilitator collectionViewWillEditCellsAtIndexPaths:indexPaths batched:YES]; [_batchUpdateBlocks addObject:^{ [super insertItemsAtIndexPaths:indexPaths]; }]; } else { + [_layoutFacilitator collectionViewWillEditCellsAtIndexPaths:indexPaths batched:NO]; [UIView performWithoutAnimation:^{ [super insertItemsAtIndexPaths:indexPaths]; }]; @@ -884,16 +891,17 @@ static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell"; - (void)rangeController:(ASRangeController *)rangeController didDeleteNodes:(NSArray *)nodes atIndexPaths:(NSArray *)indexPaths withAnimationOptions:(ASDataControllerAnimationOptions)animationOptions { ASDisplayNodeAssertMainThread(); - [_layoutFacilitator collectionViewEditingCellsAtIndexPaths:indexPaths]; if (!self.asyncDataSource || _superIsPendingDataLoad) { return; // if the asyncDataSource has become invalid while we are processing, ignore this request to avoid crashes } if (_performingBatchUpdates) { + [_layoutFacilitator collectionViewWillEditCellsAtIndexPaths:indexPaths batched:YES]; [_batchUpdateBlocks addObject:^{ [super deleteItemsAtIndexPaths:indexPaths]; }]; } else { + [_layoutFacilitator collectionViewWillEditCellsAtIndexPaths:indexPaths batched:NO]; [UIView performWithoutAnimation:^{ [super deleteItemsAtIndexPaths:indexPaths]; }]; @@ -903,16 +911,17 @@ static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell"; - (void)rangeController:(ASRangeController *)rangeController didInsertSectionsAtIndexSet:(NSIndexSet *)indexSet withAnimationOptions:(ASDataControllerAnimationOptions)animationOptions { ASDisplayNodeAssertMainThread(); - [_layoutFacilitator collectionViewEditingSectionsAtIndexSet:indexSet]; if (!self.asyncDataSource || _superIsPendingDataLoad) { return; // if the asyncDataSource has become invalid while we are processing, ignore this request to avoid crashes } if (_performingBatchUpdates) { + [_layoutFacilitator collectionViewWillEditSectionsAtIndexSet:indexSet batched:YES]; [_batchUpdateBlocks addObject:^{ [super insertSections:indexSet]; }]; } else { + [_layoutFacilitator collectionViewWillEditSectionsAtIndexSet:indexSet batched:NO]; [UIView performWithoutAnimation:^{ [super insertSections:indexSet]; }]; @@ -922,16 +931,17 @@ static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell"; - (void)rangeController:(ASRangeController *)rangeController didDeleteSectionsAtIndexSet:(NSIndexSet *)indexSet withAnimationOptions:(ASDataControllerAnimationOptions)animationOptions { ASDisplayNodeAssertMainThread(); - [_layoutFacilitator collectionViewEditingSectionsAtIndexSet:indexSet]; if (!self.asyncDataSource || _superIsPendingDataLoad) { return; // if the asyncDataSource has become invalid while we are processing, ignore this request to avoid crashes } if (_performingBatchUpdates) { + [_layoutFacilitator collectionViewWillEditSectionsAtIndexSet:indexSet batched:YES]; [_batchUpdateBlocks addObject:^{ [super deleteSections:indexSet]; }]; } else { + [_layoutFacilitator collectionViewWillEditSectionsAtIndexSet:indexSet batched:NO]; [UIView performWithoutAnimation:^{ [super deleteSections:indexSet]; }]; diff --git a/AsyncDisplayKit/ASCollectionViewLayoutFacilitatorProtocol.h b/AsyncDisplayKit/ASCollectionViewLayoutFacilitatorProtocol.h index 719c9841..514df974 100644 --- a/AsyncDisplayKit/ASCollectionViewLayoutFacilitatorProtocol.h +++ b/AsyncDisplayKit/ASCollectionViewLayoutFacilitatorProtocol.h @@ -17,13 +17,28 @@ /** * Inform that the collectionView is editing the cells at a list of indexPaths + * + * @param indexPaths, an array of NSIndexPath objects of cells being/will be edited. + * @param isBatched, indicates whether the editing operation will be batched by the collectionView + * + * NOTE: when isBatched, used in combination with -collectionViewWillPerformBatchUpdates */ -- (void)collectionViewEditingCellsAtIndexPaths:(NSArray *)indexPaths; +- (void)collectionViewWillEditCellsAtIndexPaths:(NSArray *)indexPaths batched:(BOOL)isBatched; /** * Inform that the collectionView is editing the sections at a set of indexes + * + * @param indexes, an NSIndexSet of section indexes being/will be edited. + * @param isBatched, indicates whether the editing operation will be batched by the collectionView + * + * NOTE: when isBatched, used in combination with -collectionViewWillPerformBatchUpdates */ -- (void)collectionViewEditingSectionsAtIndexSet:(NSIndexSet *)indexes; +- (void)collectionViewWillEditSectionsAtIndexSet:(NSIndexSet *)indexes batched:(BOOL)batched; + +/** + * Informs the delegate that the collectionView is about to call performBatchUpdates + */ +- (void)collectionViewWillPerformBatchUpdates; @end diff --git a/AsyncDisplayKit/Details/ASCollectionInternal.h b/AsyncDisplayKit/Details/ASCollectionInternal.h index a0aff1e5..55e99d6a 100644 --- a/AsyncDisplayKit/Details/ASCollectionInternal.h +++ b/AsyncDisplayKit/Details/ASCollectionInternal.h @@ -8,11 +8,13 @@ #import "ASCollectionView.h" #import "ASCollectionNode.h" +#import "ASDataController.h" #import "ASRangeController.h" @interface ASCollectionView () - (instancetype)_initWithFrame:(CGRect)frame collectionViewLayout:(UICollectionViewLayout *)layout layoutFacilitator:(id)layoutFacilitator ownedByNode:(BOOL)ownedByNode; @property (nonatomic, weak, readwrite) ASCollectionNode *collectionNode; +@property (nonatomic, strong, readonly) ASDataController *dataController; @property (nonatomic, strong, readonly) ASRangeController *rangeController; @end