mirror of
https://github.com/Instagram/IGListKit
synced 2026-05-06 06:58:26 +00:00
merge IGListUpdatingDelegateExperimental into IGListUpdatingDelegate
Summary: Now that the new updater has shipped, lets update `IGListUpdatingDelegate` with the new methods: * `-performExperimentalUpdateAnimated` is the new section update method (renaming coming in the next diff) * `-performDataSourceChange` lets us safely update the `UICollectionView` dataSource Also, something I've been wanting to do for a long time, lets group related methods in `IGListUpdatingDelegate.h`. Reviewed By: Haud Differential Revision: D25884780 fbshipit-source-id: 5d9201ace8bf6b281d71ff03463cb7c911e7f967
This commit is contained in:
parent
247e7cac65
commit
43af8838df
9 changed files with 127 additions and 240 deletions
|
|
@ -15,7 +15,7 @@
|
|||
#import "IGListDebugger.h"
|
||||
#import "IGListSectionControllerInternal.h"
|
||||
#import "IGListTransitionData.h"
|
||||
#import "IGListUpdatingDelegateExperimental.h"
|
||||
#import "IGListUpdatingDelegate.h"
|
||||
#import "UICollectionViewLayout+InteractiveReordering.h"
|
||||
#import "UIScrollView+IGListKit.h"
|
||||
|
||||
|
|
@ -24,8 +24,6 @@
|
|||
// An array of blocks to execute once batch updates are finished
|
||||
NSMutableArray<void (^)(void)> *_queuedCompletionBlocks;
|
||||
NSHashTable<id<IGListAdapterUpdateListener>> *_updateListeners;
|
||||
// Temporary property while we experiment with a new updater.
|
||||
id<IGListUpdatingDelegateExperimental> _experimentalUpdater;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
|
|
@ -56,7 +54,6 @@
|
|||
|
||||
_updater = updater;
|
||||
_viewController = viewController;
|
||||
_experimentalUpdater = [updater conformsToProtocol:@protocol(IGListUpdatingDelegateExperimental)] ? (id<IGListUpdatingDelegateExperimental>)updater : nil;
|
||||
|
||||
[IGListDebugger trackAdapter:self];
|
||||
}
|
||||
|
|
@ -97,35 +94,26 @@
|
|||
_registeredSupplementaryViewIdentifiers = [NSMutableSet new];
|
||||
_registeredSupplementaryViewNibNames = [NSMutableSet new];
|
||||
|
||||
const BOOL settingFirstCollectionView = _collectionView == nil;
|
||||
// We can't just swap out the collectionView, because we might have on-going or pending updates.
|
||||
// `_updater` can take care of that by wrapping the change in `performDataSourceChange`.
|
||||
[_updater performDataSourceChange:^{
|
||||
if (self->_collectionView.dataSource == self) {
|
||||
// Since we're not going to sync the previous collectionView anymore, lets not be its dataSource.
|
||||
self->_collectionView.dataSource = nil;
|
||||
}
|
||||
self->_collectionView = collectionView;
|
||||
self->_collectionView.dataSource = self;
|
||||
|
||||
if (_experimentalUpdater) {
|
||||
// We can't just swap out the collectionView, because we might have on-going or pending updates.
|
||||
// `_experimentalUpdater` can take care of that by wrapping the change in `performDataSourceChange`.
|
||||
|
||||
[_experimentalUpdater performDataSourceChange:^{
|
||||
if (self->_collectionView.dataSource == self) {
|
||||
// Since we're not going to sync the previous collectionView anymore, lets not be its dataSource.
|
||||
self->_collectionView.dataSource = nil;
|
||||
}
|
||||
self->_collectionView = collectionView;
|
||||
self->_collectionView.dataSource = self;
|
||||
|
||||
[self _updateCollectionViewDelegate];
|
||||
|
||||
// Sync the dataSource <> adapter for a couple of reasons:
|
||||
// 1. We might not have synced on -setDataSource, so now is the time to try again.
|
||||
// 2. Any in-flight `performUpdatesAnimated` were cancelled, so lets make sure we have the latest data.
|
||||
[self _updateObjects];
|
||||
|
||||
// The sync between the collectionView <> adapter will happen automically, since
|
||||
// we just changed the `collectionView.dataSource`.
|
||||
}];
|
||||
} else {
|
||||
_collectionView = collectionView;
|
||||
_collectionView.dataSource = self;
|
||||
[self _updateCollectionViewDelegate];
|
||||
}
|
||||
|
||||
// Sync the dataSource <> adapter for a couple of reasons:
|
||||
// 1. We might not have synced on -setDataSource, so now is the time to try again.
|
||||
// 2. Any in-flight `performUpdatesAnimated` were cancelled, so lets make sure we have the latest data.
|
||||
[self _updateObjects];
|
||||
|
||||
// The sync between the collectionView <> adapter will happen automically, since
|
||||
// we just changed the `collectionView.dataSource`.
|
||||
}];
|
||||
|
||||
if (@available(iOS 10.0, tvOS 10, *)) {
|
||||
_collectionView.prefetchingEnabled = NO;
|
||||
|
|
@ -133,10 +121,6 @@
|
|||
|
||||
[_collectionView.collectionViewLayout ig_hijackLayoutInteractiveReorderingMethodForAdapter:self];
|
||||
[_collectionView.collectionViewLayout invalidateLayout];
|
||||
|
||||
if (!_experimentalUpdater && settingFirstCollectionView) {
|
||||
[self _updateObjectsIfHasDataSource];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -145,24 +129,19 @@
|
|||
return;
|
||||
}
|
||||
|
||||
if (_experimentalUpdater) {
|
||||
[_experimentalUpdater performDataSourceChange:^{
|
||||
self->_dataSource = dataSource;
|
||||
[_updater performDataSourceChange:^{
|
||||
self->_dataSource = dataSource;
|
||||
|
||||
// Invalidate the collectionView internal section & item counts, as if its dataSource changed.
|
||||
self->_collectionView.dataSource = nil;
|
||||
self->_collectionView.dataSource = self;
|
||||
// Invalidate the collectionView internal section & item counts, as if its dataSource changed.
|
||||
self->_collectionView.dataSource = nil;
|
||||
self->_collectionView.dataSource = self;
|
||||
|
||||
// Sync the dataSource <> adapter
|
||||
[self _updateObjects];
|
||||
// Sync the dataSource <> adapter
|
||||
[self _updateObjects];
|
||||
|
||||
// The sync between the collectionView <> adapter will happen automically, since
|
||||
// we just changed the `collectionView.dataSource`.
|
||||
}];
|
||||
} else {
|
||||
_dataSource = dataSource;
|
||||
[self _updateObjectsIfHasDataSource];
|
||||
}
|
||||
// The sync between the collectionView <> adapter will happen automically, since
|
||||
// we just changed the `collectionView.dataSource`.
|
||||
}];
|
||||
}
|
||||
|
||||
// reset and configure the delegate proxy whenever this property is set
|
||||
|
|
@ -186,13 +165,6 @@
|
|||
}
|
||||
}
|
||||
|
||||
- (void)_updateObjectsIfHasDataSource {
|
||||
// This is to keep the existing logic while testing `experimentalUpdater`
|
||||
if (_dataSource != nil) {
|
||||
[self _updateObjects];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)_updateObjects {
|
||||
if (_collectionView == nil) {
|
||||
// If we don't have a collectionView, we can't do much.
|
||||
|
|
@ -375,66 +347,8 @@
|
|||
return;
|
||||
}
|
||||
|
||||
__weak __typeof__(self) weakSelf = self;
|
||||
IGListUpdaterCompletion outerCompletionBlock = ^(BOOL finished){
|
||||
__typeof__(self) strongSelf = weakSelf;
|
||||
if (strongSelf == nil) {
|
||||
IGLK_BLOCK_CALL_SAFE(completion,finished);
|
||||
return;
|
||||
}
|
||||
|
||||
// release the previous items
|
||||
strongSelf.previousSectionMap = nil;
|
||||
[strongSelf _notifyDidUpdate:IGListAdapterUpdateTypePerformUpdates animated:animated];
|
||||
IGLK_BLOCK_CALL_SAFE(completion,finished);
|
||||
[strongSelf _exitBatchUpdates];
|
||||
};
|
||||
|
||||
[self _enterBatchUpdates];
|
||||
if (_experimentalUpdater) {
|
||||
[self _performExperimentalUpdatesWithUpdater:_experimentalUpdater
|
||||
dataSource:dataSource
|
||||
animated:animated
|
||||
completion:outerCompletionBlock];
|
||||
} else {
|
||||
[self _performRegularUpdatesWithUpdater:updater
|
||||
dataSource:dataSource
|
||||
animated:animated
|
||||
completion:outerCompletionBlock];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)_performRegularUpdatesWithUpdater:(id<IGListUpdatingDelegate>)updater
|
||||
dataSource:(id<IGListAdapterDataSource>)dataSource
|
||||
animated:(BOOL)animated
|
||||
completion:(IGListUpdaterCompletion)completion {
|
||||
NSArray *fromObjects = self.sectionMap.objects;
|
||||
|
||||
__weak __typeof__(self) weakSelf = self;
|
||||
IGListToObjectBlock toObjectsBlock = ^NSArray *{
|
||||
__typeof__(self) strongSelf = weakSelf;
|
||||
if (strongSelf == nil) {
|
||||
return nil;
|
||||
}
|
||||
return [dataSource objectsForListAdapter:strongSelf];
|
||||
};
|
||||
|
||||
[updater performUpdateWithCollectionViewBlock:[self _collectionViewBlock]
|
||||
fromObjects:fromObjects
|
||||
toObjectsBlock:toObjectsBlock
|
||||
animated:animated
|
||||
objectTransitionBlock:^(NSArray *toObjects) {
|
||||
// temporarily capture the item map that we are transitioning from in case
|
||||
// there are any item deletes at the same
|
||||
weakSelf.previousSectionMap = [weakSelf.sectionMap copy];
|
||||
[weakSelf _updateObjects:toObjects dataSource:dataSource];
|
||||
} completion:completion];
|
||||
}
|
||||
|
||||
- (void)_performExperimentalUpdatesWithUpdater:(id<IGListUpdatingDelegateExperimental>)updater
|
||||
dataSource:(id<IGListAdapterDataSource>)dataSource
|
||||
animated:(BOOL)animated
|
||||
completion:(IGListUpdaterCompletion)completion {
|
||||
__weak __typeof__(self) weakSelf = self;
|
||||
IGListTransitionDataBlock dataBlock = ^IGListTransitionData *{
|
||||
__typeof__(self) strongSelf = weakSelf;
|
||||
|
|
@ -452,15 +366,29 @@
|
|||
}
|
||||
// temporarily capture the item map that we are transitioning from in case
|
||||
// there are any item deletes at the same
|
||||
strongSelf.previousSectionMap = [weakSelf.sectionMap copy];
|
||||
strongSelf.previousSectionMap = [strongSelf.sectionMap copy];
|
||||
[strongSelf _updateWithData:data];
|
||||
};
|
||||
|
||||
IGListUpdaterCompletion outerCompletionBlock = ^(BOOL finished){
|
||||
__typeof__(self) strongSelf = weakSelf;
|
||||
if (strongSelf == nil) {
|
||||
IGLK_BLOCK_CALL_SAFE(completion,finished);
|
||||
return;
|
||||
}
|
||||
|
||||
// release the previous items
|
||||
strongSelf.previousSectionMap = nil;
|
||||
[strongSelf _notifyDidUpdate:IGListAdapterUpdateTypePerformUpdates animated:animated];
|
||||
IGLK_BLOCK_CALL_SAFE(completion,finished);
|
||||
[strongSelf _exitBatchUpdates];
|
||||
};
|
||||
|
||||
[updater performExperimentalUpdateAnimated:animated
|
||||
collectionViewBlock:[self _collectionViewBlock]
|
||||
dataBlock:dataBlock
|
||||
applyDataBlock:applyDataBlock
|
||||
completion:completion];
|
||||
completion:outerCompletionBlock];
|
||||
}
|
||||
|
||||
- (void)reloadDataWithCompletion:(nullable IGListUpdaterCompletion)completion {
|
||||
|
|
@ -795,7 +723,7 @@
|
|||
return; // will be called again when update block completes
|
||||
}
|
||||
|
||||
if (!shouldHide || !_experimentalUpdater) {
|
||||
if (!shouldHide) {
|
||||
UIView *backgroundView = [self.dataSource emptyViewForListAdapter:self];
|
||||
// don't do anything if the client is using the same view
|
||||
if (backgroundView != _collectionView.backgroundView) {
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@
|
|||
|
||||
#import <IGListDiffKit/IGListMacros.h>
|
||||
#import <IGListKit/IGListAdapterUpdaterCompatible.h>
|
||||
#import <IGListKit/IGListUpdatingDelegateExperimental.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
|
|
@ -23,7 +22,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
*/
|
||||
IGLK_SUBCLASSING_RESTRICTED
|
||||
NS_SWIFT_NAME(ListAdapterUpdater)
|
||||
@interface IGListAdapterUpdater : NSObject <IGListAdapterUpdaterCompatible, IGListUpdatingDelegateExperimental>
|
||||
@interface IGListAdapterUpdater : NSObject <IGListAdapterUpdaterCompatible>
|
||||
|
||||
@end
|
||||
|
||||
|
|
|
|||
|
|
@ -147,16 +147,6 @@ static NSUInteger IGListIdentifierHash(const void *item, NSUInteger (*size)(cons
|
|||
return functions;
|
||||
}
|
||||
|
||||
- (void)performUpdateWithCollectionViewBlock:(IGListCollectionViewBlock)collectionViewBlock
|
||||
fromObjects:(NSArray *)fromObjects
|
||||
toObjectsBlock:(IGListToObjectBlock)toObjectsBlock
|
||||
animated:(BOOL)animated
|
||||
objectTransitionBlock:(IGListObjectTransitionBlock)objectTransitionBlock
|
||||
completion:(IGListUpdatingCompletion)completion {
|
||||
IGFailAssert(@"IGListExperimentalAdapterUpdater works with IGListUpdatingDelegateExperimental and doesn't implement the regular -performUpdateWithCollectionViewBlock method");
|
||||
completion(NO);
|
||||
}
|
||||
|
||||
- (void)performExperimentalUpdateAnimated:(BOOL)animated
|
||||
collectionViewBlock:(IGListCollectionViewBlock)collectionViewBlock
|
||||
dataBlock:(IGListTransitionDataBlock)dataBlock
|
||||
|
|
|
|||
|
|
@ -15,15 +15,14 @@
|
|||
return [NSPointerFunctions pointerFunctionsWithOptions:NSPointerFunctionsObjectPersonality];
|
||||
}
|
||||
|
||||
- (void)performUpdateWithCollectionViewBlock:(IGListCollectionViewBlock)collectionViewBlock
|
||||
fromObjects:(NSArray *)fromObjects
|
||||
toObjectsBlock:(IGListToObjectBlock)toObjectsBlock
|
||||
animated:(BOOL)animated
|
||||
objectTransitionBlock:(IGListObjectTransitionBlock)objectTransitionBlock
|
||||
completion:(IGListUpdatingCompletion)completion {
|
||||
if (toObjectsBlock != nil) {
|
||||
NSArray *toObjects = toObjectsBlock() ?: @[];
|
||||
objectTransitionBlock(toObjects);
|
||||
- (void)performExperimentalUpdateAnimated:(BOOL)animated
|
||||
collectionViewBlock:(IGListCollectionViewBlock)collectionViewBlock
|
||||
dataBlock:(IGListTransitionDataBlock)dataBlock
|
||||
applyDataBlock:(IGListTransitionDataApplyBlock)applyDataBlock
|
||||
completion:(nullable IGListUpdatingCompletion)completion {
|
||||
IGListTransitionData *sectionData = dataBlock ? dataBlock() : nil;
|
||||
if (sectionData != nil) {
|
||||
applyDataBlock(sectionData);
|
||||
}
|
||||
[self _synchronousReloadDataWithCollectionView:collectionViewBlock()];
|
||||
if (completion) {
|
||||
|
|
@ -42,6 +41,20 @@
|
|||
}
|
||||
}
|
||||
|
||||
- (void)performDataSourceChange:(IGListDataSourceChangeBlock)block {
|
||||
// A `UICollectionView` dataSource change will automatically invalidate
|
||||
// its data, so no need to do anything else.
|
||||
block();
|
||||
}
|
||||
|
||||
- (void)reloadDataWithCollectionViewBlock:(IGListCollectionViewBlock)collectionViewBlock reloadUpdateBlock:(IGListReloadUpdateBlock)reloadUpdateBlock completion:(IGListUpdatingCompletion)completion {
|
||||
reloadUpdateBlock();
|
||||
[self _synchronousReloadDataWithCollectionView:collectionViewBlock()];
|
||||
if (completion) {
|
||||
completion(YES);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)insertItemsIntoCollectionView:(UICollectionView *)collectionView indexPaths:(NSArray<NSIndexPath *> *)indexPaths {
|
||||
[self _synchronousReloadDataWithCollectionView:collectionView];
|
||||
}
|
||||
|
|
@ -62,14 +75,6 @@
|
|||
[self _synchronousReloadDataWithCollectionView:collectionView];
|
||||
}
|
||||
|
||||
- (void)reloadDataWithCollectionViewBlock:(IGListCollectionViewBlock)collectionViewBlock reloadUpdateBlock:(IGListReloadUpdateBlock)reloadUpdateBlock completion:(IGListUpdatingCompletion)completion {
|
||||
reloadUpdateBlock();
|
||||
[self _synchronousReloadDataWithCollectionView:collectionViewBlock()];
|
||||
if (completion) {
|
||||
completion(YES);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)reloadCollectionView:(UICollectionView *)collectionView sections:(NSIndexSet *)sections {
|
||||
[self _synchronousReloadDataWithCollectionView:collectionView];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@class IGListTransitionData;
|
||||
@protocol IGListDiffable;
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
|
@ -47,6 +48,18 @@ typedef UICollectionView * _Nullable (^IGListCollectionViewBlock)(void);
|
|||
NS_SWIFT_NAME(ListDataSourceChangeBlock)
|
||||
typedef void (^IGListDataSourceChangeBlock)(void);
|
||||
|
||||
/// A block that returns the `IGListTransitionData` needed before an update.
|
||||
NS_SWIFT_NAME(ListTransitionDataBlock)
|
||||
typedef IGListTransitionData * _Nullable (^IGListTransitionDataBlock)(void);
|
||||
|
||||
/**
|
||||
A block to be called when the adapter applies changes to the collection view.
|
||||
|
||||
@param data The new data that contains the from/to objects.
|
||||
*/
|
||||
NS_SWIFT_NAME(ListTransitionDataApplyBlock)
|
||||
typedef void (^IGListTransitionDataApplyBlock)(IGListTransitionData *data);
|
||||
|
||||
/**
|
||||
Implement this protocol in order to handle both section and row based update events. Implementation should forward or
|
||||
coalesce these events to a backing store or collection.
|
||||
|
|
@ -69,29 +82,59 @@ NS_SWIFT_NAME(ListUpdatingDelegate)
|
|||
- (NSPointerFunctions *)objectLookupPointerFunctions;
|
||||
|
||||
/**
|
||||
Tells the delegate to perform a section transition from an old array of objects to a new one.
|
||||
Perform a **section** update from an old array of objects to a new one.
|
||||
|
||||
@param collectionViewBlock A block returning the collecion view to perform updates on.
|
||||
@param fromObjects The previous objects in the collection view. Objects must conform to `IGListDiffable`.
|
||||
@param toObjectsBlock A block returning the new objects in the collection view. Objects must conform to `IGListDiffable`.
|
||||
@param animated A flag indicating if the transition should be animated.
|
||||
@param objectTransitionBlock A block that must be called when the adapter applies changes to the collection view.
|
||||
@param collectionViewBlock A block returning the collecion view to perform updates on.
|
||||
@param dataBlock A block that returns the section information (ex: from and to objects)
|
||||
@param applyDataBlock A block that must be called when the adapter applies changes to the collection view.
|
||||
@param completion A completion block to execute when the update is finished.
|
||||
|
||||
@note Implementations determine how to transition between objects. You can perform a diff on the objects, reload
|
||||
each section, or simply call `-reloadData` on the collection view. In the end, the collection view must be setup with a
|
||||
section for each object in the `toObjects` array.
|
||||
|
||||
The `objectTransitionBlock` block should be called prior to making any `UICollectionView` updates, passing in the `toObjects`
|
||||
The `applyDataBlock` block should be called prior to making any `UICollectionView` updates, passing in the `toObjects`
|
||||
that the updater is applying.
|
||||
*/
|
||||
- (void)performExperimentalUpdateAnimated:(BOOL)animated
|
||||
collectionViewBlock:(IGListCollectionViewBlock)collectionViewBlock
|
||||
dataBlock:(IGListTransitionDataBlock)dataBlock
|
||||
applyDataBlock:(IGListTransitionDataApplyBlock)applyDataBlock
|
||||
completion:(nullable IGListUpdatingCompletion)completion;
|
||||
|
||||
/**
|
||||
Perform an **item** update block in the collection view.
|
||||
|
||||
@param collectionViewBlock A block returning the collecion view to perform updates on.
|
||||
@param animated A flag indicating if the transition should be animated.
|
||||
@param itemUpdates A block containing all of the updates.
|
||||
@param completion A completion block to execute when the update is finished.
|
||||
*/
|
||||
- (void)performUpdateWithCollectionViewBlock:(IGListCollectionViewBlock)collectionViewBlock
|
||||
fromObjects:(nullable NSArray<id <IGListDiffable>> *)fromObjects
|
||||
toObjectsBlock:(nullable IGListToObjectBlock)toObjectsBlock
|
||||
animated:(BOOL)animated
|
||||
objectTransitionBlock:(IGListObjectTransitionBlock)objectTransitionBlock
|
||||
itemUpdates:(IGListItemUpdateBlock)itemUpdates
|
||||
completion:(nullable IGListUpdatingCompletion)completion;
|
||||
|
||||
/**
|
||||
Perform a `[UICollectionView setDataSource:...]` swap within this block. It gives the updater the chance to cancel or
|
||||
execute any on-going updates. The block should be executed synchronously.
|
||||
|
||||
@param block The block that will actuallty change the `dataSource`
|
||||
*/
|
||||
- (void)performDataSourceChange:(IGListDataSourceChangeBlock)block;
|
||||
|
||||
/**
|
||||
Completely reload data in the collection.
|
||||
|
||||
@param collectionViewBlock A block returning the collecion view to reload.
|
||||
@param reloadUpdateBlock A block that must be called when the adapter reloads the collection view.
|
||||
@param completion A completion block to execute when the reload is finished.
|
||||
*/
|
||||
- (void)reloadDataWithCollectionViewBlock:(IGListCollectionViewBlock)collectionViewBlock
|
||||
reloadUpdateBlock:(IGListReloadUpdateBlock)reloadUpdateBlock
|
||||
completion:(nullable IGListUpdatingCompletion)completion;
|
||||
|
||||
/**
|
||||
Tells the delegate to perform item inserts at the given index paths.
|
||||
|
||||
|
|
@ -145,17 +188,6 @@ NS_SWIFT_NAME(ListUpdatingDelegate)
|
|||
fromIndex:(NSInteger)fromIndex
|
||||
toIndex:(NSInteger)toIndex;
|
||||
|
||||
/**
|
||||
Completely reload data in the collection.
|
||||
|
||||
@param collectionViewBlock A block returning the collecion view to reload.
|
||||
@param reloadUpdateBlock A block that must be called when the adapter reloads the collection view.
|
||||
@param completion A completion block to execute when the reload is finished.
|
||||
*/
|
||||
- (void)reloadDataWithCollectionViewBlock:(IGListCollectionViewBlock)collectionViewBlock
|
||||
reloadUpdateBlock:(IGListReloadUpdateBlock)reloadUpdateBlock
|
||||
completion:(nullable IGListUpdatingCompletion)completion;
|
||||
|
||||
/**
|
||||
Completely reload each section in the collection view.
|
||||
|
||||
|
|
@ -164,19 +196,6 @@ NS_SWIFT_NAME(ListUpdatingDelegate)
|
|||
*/
|
||||
- (void)reloadCollectionView:(UICollectionView *)collectionView sections:(NSIndexSet *)sections;
|
||||
|
||||
/**
|
||||
Perform an item update block in the collection view.
|
||||
|
||||
@param collectionViewBlock A block returning the collecion view to perform updates on.
|
||||
@param animated A flag indicating if the transition should be animated.
|
||||
@param itemUpdates A block containing all of the updates.
|
||||
@param completion A completion block to execute when the update is finished.
|
||||
*/
|
||||
- (void)performUpdateWithCollectionViewBlock:(IGListCollectionViewBlock)collectionViewBlock
|
||||
animated:(BOOL)animated
|
||||
itemUpdates:(IGListItemUpdateBlock)itemUpdates
|
||||
completion:(nullable IGListUpdatingCompletion)completion;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
|
|
|||
|
|
@ -1,54 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
#import "IGListUpdatingDelegate.h"
|
||||
|
||||
@class IGListTransitionData;
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/// A block that returns the `IGListTransitionData` needed before an update.
|
||||
NS_SWIFT_NAME(ListTransitionDataBlock)
|
||||
typedef IGListTransitionData * _Nullable (^IGListTransitionDataBlock)(void);
|
||||
|
||||
/**
|
||||
A block to be called when the adapter applies changes to the collection view.
|
||||
|
||||
@param data The new data that contains the from/to objects.
|
||||
*/
|
||||
NS_SWIFT_NAME(ListTransitionDataApplyBlock)
|
||||
typedef void (^IGListTransitionDataApplyBlock)(IGListTransitionData *data);
|
||||
|
||||
/**
|
||||
Temporary experimental version of `IGListUpdatingDelegate`
|
||||
*/
|
||||
NS_SWIFT_NAME(ListUpdatingDelegateExperimental)
|
||||
@protocol IGListUpdatingDelegateExperimental <IGListUpdatingDelegate>
|
||||
|
||||
/**
|
||||
Experimental version of `performUpdateWithCollectionViewBlock` that uses `IGListTransitionData` to make updates safer.
|
||||
The adapter will use this method instead of the regular `performUpdateWithCollectionViewBlock` if implemented.
|
||||
*/
|
||||
- (void)performExperimentalUpdateAnimated:(BOOL)animated
|
||||
collectionViewBlock:(IGListCollectionViewBlock)collectionViewBlock
|
||||
dataBlock:(IGListTransitionDataBlock)dataBlock
|
||||
applyDataBlock:(IGListTransitionDataApplyBlock)applyDataBlock
|
||||
completion:(nullable IGListUpdatingCompletion)completion;
|
||||
|
||||
/**
|
||||
Perform a `[UICollectionView setDataSource:...]` swap within this block. It gives the updater the chance to cancel or
|
||||
execute any on-going updates. The block will be executed synchronously.
|
||||
|
||||
@param block The block that will actuallty change the `dataSource`
|
||||
*/
|
||||
- (void)performDataSourceChange:(IGListDataSourceChangeBlock)block;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
|
@ -9,7 +9,6 @@
|
|||
|
||||
#import <IGListDiffKit/IGListMacros.h>
|
||||
#import <IGListKit/IGListUpdatingDelegate.h>
|
||||
#import <IGListKit/IGListUpdatingDelegateExperimental.h>
|
||||
|
||||
#import "IGListUpdateTransactable.h"
|
||||
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@
|
|||
|
||||
#import <IGListDiffKit/IGListMacros.h>
|
||||
#import <IGListKit/IGListUpdatingDelegate.h>
|
||||
#import <IGListKit/IGListUpdatingDelegateExperimental.h>
|
||||
|
||||
#import "IGListUpdateTransactable.h"
|
||||
|
||||
|
|
|
|||
|
|
@ -176,8 +176,8 @@
|
|||
((IGListTestAdapterDataSource *)self.dataSource).backgroundView = background;
|
||||
__block BOOL executed = NO;
|
||||
[self.adapter reloadDataWithCompletion:^(BOOL finished) {
|
||||
XCTAssertTrue(self.adapter.collectionView.backgroundView.hidden, @"Background view should be hidden");
|
||||
XCTAssertEqualObjects(background, self.adapter.collectionView.backgroundView, @"Background view not correctly assigned");
|
||||
UIView *backgroundViewAfterReload = self.adapter.collectionView.backgroundView;
|
||||
XCTAssertTrue(!backgroundViewAfterReload || backgroundViewAfterReload.hidden, @"Background view should be hidden");
|
||||
|
||||
self.dataSource.objects = @[];
|
||||
[self.adapter reloadDataWithCompletion:^(BOOL finished2) {
|
||||
|
|
@ -358,7 +358,8 @@
|
|||
self.dataSource.objects = @[@1];
|
||||
((IGListTestAdapterDataSource *)self.dataSource).backgroundView = [UIView new];
|
||||
[self.adapter reloadDataWithCompletion:nil];
|
||||
XCTAssertTrue(self.collectionView.backgroundView.hidden);
|
||||
UIView *backgroundView = self.adapter.collectionView.backgroundView;
|
||||
XCTAssertTrue(!backgroundView || backgroundView.hidden);
|
||||
IGListTestSection *sectionController = [self.adapter sectionControllerForObject:@(1)];
|
||||
sectionController.items = 0;
|
||||
[self.adapter deleteInSectionController:sectionController atIndexes:[NSIndexSet indexSetWithIndex:0]];
|
||||
|
|
@ -380,7 +381,8 @@
|
|||
self.dataSource.objects = @[@1, @2];
|
||||
((IGListTestAdapterDataSource *)self.dataSource).backgroundView = [UIView new];
|
||||
[self.adapter reloadDataWithCompletion:nil];
|
||||
XCTAssertTrue(self.collectionView.backgroundView.hidden);
|
||||
UIView *backgroundView = self.adapter.collectionView.backgroundView;
|
||||
XCTAssertTrue(!backgroundView || backgroundView.hidden);
|
||||
IGListTestSection *firstSectionController = [self.adapter sectionControllerForObject:@(1)];
|
||||
IGListTestSection *secondSectionController = [self.adapter sectionControllerForObject:@(2)];
|
||||
XCTestExpectation *expectation = [self expectationWithDescription:NSStringFromSelector(_cmd)];
|
||||
|
|
|
|||
Loading…
Reference in a new issue