clean up IGListReloadTransaction

Summary:
Using blocks can be nice, but here it causes a couple problems:
* The order of execution is a bit hard to follow. For example, in `-begin`, the very first thing we see defined is `executeCompletionBlocks` which is the last thing actually called. `IGListReloadTransaction` isn't too complex, but it gets even harder to follow in `IGListBatchUpdateTransaction`.
* It makes crash and assert reports hard to understand, because the stack includes mostly block names.

So lets turn blocks into methods.

Reviewed By: patters

Differential Revision: D23151918

fbshipit-source-id: 3ac4c77e9978c2700fd6744f084f624d27f0d300
This commit is contained in:
Maxime Ollivier 2020-09-08 09:06:16 -07:00 committed by Facebook GitHub Bot
parent 13ad185227
commit d8a728ec7f

View file

@ -11,8 +11,8 @@
@interface IGListReloadTransaction ()
// Given
@property (nonatomic, copy, readonly) IGListCollectionViewBlock collectionViewBlock;
@property (nonatomic, weak, readonly, nullable) id<IGListAdapterUpdaterCompatible> updater;
@property (nonatomic, copy, readonly) UICollectionView *collectionView;
@property (nonatomic, weak, readonly) id<IGListAdapterUpdaterCompatible> updater;
@property (nonatomic, weak, readonly, nullable) id<IGListAdapterUpdaterDelegate> delegate;
@property (nonatomic, copy, readonly) IGListReloadUpdateBlock reloadBlock;
@property (nonatomic, copy, readonly) NSArray<IGListItemUpdateBlock> *itemUpdateBlocks;
@ -26,12 +26,12 @@
- (instancetype)initWithCollectionViewBlock:(IGListCollectionViewBlock)collectionViewBlock
updater:(id<IGListAdapterUpdaterCompatible>)updater
delegate:(nullable id<IGListAdapterUpdaterDelegate>)delegate
delegate:(id<IGListAdapterUpdaterDelegate>)delegate
reloadBlock:(IGListReloadUpdateBlock)reloadBlock
itemUpdateBlocks:(NSArray<IGListItemUpdateBlock> *)itemUpdateBlocks
completionBlocks:(NSArray<IGListUpdatingCompletion> *)completionBlocks {
if (self = [super init]) {
_collectionViewBlock = [collectionViewBlock copy];
_collectionView = collectionViewBlock ? collectionViewBlock() : nil;
_updater = updater;
_delegate = delegate;
_reloadBlock = [reloadBlock copy];
@ -43,69 +43,54 @@
return self;
}
#pragma mark - IGListUpdateTransactable
#pragma mark - Update
- (void)begin {
IGListCollectionViewBlock collectionViewBlock = self.collectionViewBlock;
id<IGListAdapterUpdaterCompatible> updater = self.updater;
id<IGListAdapterUpdaterDelegate> delegate = self.delegate;
void (^reloadUpdates)(void) = self.reloadBlock;
NSArray *itemUpdateBlocks = self.itemUpdateBlocks;
NSArray *completionBlocks = self.completionBlocks;
void (^executeCompletionBlocks)(BOOL) = ^(BOOL finished) {
for (IGListUpdatingCompletion block in completionBlocks) {
block(finished);
}
// Execute any completion blocks from item updates. Added after item blocks are executed in order to capture any
// re-entrant updates.
NSArray *inUpdateCompletionBlocks = [self.inUpdateCompletionBlocks copy];
for (IGListUpdatingCompletion block in inUpdateCompletionBlocks) {
block(finished);
}
self.state = IGListBatchUpdateStateIdle;
};
// bail early if the collection view has been deallocated in the time since the update was queued
UICollectionView *collectionView = collectionViewBlock();
if (collectionView == nil) {
executeCompletionBlocks(NO);
[delegate listAdapterUpdater:updater didFinishWithoutUpdatesWithCollectionView:collectionView];
if (self.collectionView == nil) {
[self.delegate listAdapterUpdater:self.updater didFinishWithoutUpdatesWithCollectionView:self.collectionView];
[self _executeCompletionBlocks:YES];
return;
}
// item updates must not send mutations to the collection view while we are reloading
self.state = IGListBatchUpdateStateExecutingBatchUpdateBlock;
if (reloadUpdates) {
reloadUpdates();
if (self.reloadBlock) {
self.reloadBlock();
}
// execute all stored item update blocks even if we are just calling reloadData. the actual collection view
// mutations will be discarded, but clients are encouraged to put their actual /data/ mutations inside the
// update block as well, so if we don't execute the block the changes will never happen
for (IGListItemUpdateBlock itemUpdateBlock in itemUpdateBlocks) {
for (IGListItemUpdateBlock itemUpdateBlock in self.itemUpdateBlocks) {
itemUpdateBlock();
}
self.state = IGListBatchUpdateStateExecutedBatchUpdateBlock;
[delegate listAdapterUpdater:updater willReloadDataWithCollectionView:collectionView isFallbackReload:NO];
[collectionView reloadData];
[collectionView.collectionViewLayout invalidateLayout];
[collectionView layoutIfNeeded];
[delegate listAdapterUpdater:updater didReloadDataWithCollectionView:collectionView isFallbackReload:NO];
[self.delegate listAdapterUpdater:self.updater willReloadDataWithCollectionView:self.collectionView isFallbackReload:NO];
[self.collectionView reloadData];
[self.collectionView.collectionViewLayout invalidateLayout];
[self.collectionView layoutIfNeeded];
[self.delegate listAdapterUpdater:self.updater didReloadDataWithCollectionView:self.collectionView isFallbackReload:NO];
executeCompletionBlocks(YES);
[self _executeCompletionBlocks:YES];
}
- (void)addCompletionBlock:(IGListUpdatingCompletion)completion {
if (!self.inUpdateCompletionBlocks) {
_inUpdateCompletionBlocks = [NSMutableArray new];
- (void)_executeCompletionBlocks:(BOOL)finished {
for (IGListUpdatingCompletion block in self.completionBlocks) {
block(finished);
}
[self.inUpdateCompletionBlocks addObject:completion];
// Execute any completion blocks from item updates. Added after item blocks are executed in order to capture any
// re-entrant updates.
NSArray *inUpdateCompletionBlocks = [self.inUpdateCompletionBlocks copy];
for (IGListUpdatingCompletion block in inUpdateCompletionBlocks) {
block(finished);
}
self.state = IGListBatchUpdateStateIdle;
}
#pragma mark - Item updates
@ -130,4 +115,11 @@
// no-op. Reloading all cells.
}
- (void)addCompletionBlock:(IGListUpdatingCompletion)completion {
if (!self.inUpdateCompletionBlocks) {
_inUpdateCompletionBlocks = [NSMutableArray new];
}
[self.inUpdateCompletionBlocks addObject:completion];
}
@end