mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-14 10:20:11 +00:00
Merge pull request #1525 from maicki/ASCollectionViewASTableViewRespondsToSelector
Add caching respondsToSelector calls in ASCollectionView and ASTableView
This commit is contained in:
commit
dbc68c3a8f
@ -106,9 +106,6 @@ static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell";
|
|||||||
NSMutableArray *_batchUpdateBlocks;
|
NSMutableArray *_batchUpdateBlocks;
|
||||||
|
|
||||||
BOOL _asyncDataFetchingEnabled;
|
BOOL _asyncDataFetchingEnabled;
|
||||||
BOOL _asyncDelegateImplementsScrollviewDidScroll;
|
|
||||||
BOOL _asyncDataSourceImplementsConstrainedSizeForNode;
|
|
||||||
BOOL _asyncDataSourceImplementsNodeBlockForItemAtIndexPath;
|
|
||||||
_ASCollectionViewNodeSizeInvalidationContext *_queuedNodeSizeInvalidationContext; // Main thread only
|
_ASCollectionViewNodeSizeInvalidationContext *_queuedNodeSizeInvalidationContext; // Main thread only
|
||||||
BOOL _isDeallocating;
|
BOOL _isDeallocating;
|
||||||
|
|
||||||
@ -133,6 +130,26 @@ static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell";
|
|||||||
* The collection view never queried your data source before the update to see that it actually had 0 items.
|
* The collection view never queried your data source before the update to see that it actually had 0 items.
|
||||||
*/
|
*/
|
||||||
BOOL _superIsPendingDataLoad;
|
BOOL _superIsPendingDataLoad;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
unsigned int asyncDelegateScrollViewDidScroll:1;
|
||||||
|
unsigned int asyncDelegateScrollViewWillEndDraggingWithVelocityTargetContentOffset:1;
|
||||||
|
unsigned int asyncDelegateCollectionViewWillDisplayNodeForItemAtIndexPath:1;
|
||||||
|
unsigned int asyncDelegateCollectionViewDidEndDisplayingNodeForItemAtIndexPath:1;
|
||||||
|
unsigned int asyncDelegateCollectionViewDidEndDisplayingNodeForItemAtIndexPathDeprecated:1;
|
||||||
|
unsigned int asyncDelegateCollectionViewWillBeginBatchFetchWithContext:1;
|
||||||
|
unsigned int asyncDelegateShouldBatchFetchForCollectionView:1;
|
||||||
|
} _asyncDelegateFlags;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
unsigned int asyncDataSourceConstrainedSizeForNode:1;
|
||||||
|
unsigned int asyncDataSourceNodeForItemAtIndexPath:1;
|
||||||
|
unsigned int asyncDataSourceNodeBlockForItemAtIndexPath:1;
|
||||||
|
unsigned int asyncDataSourceNumberOfSectionsInCollectionView:1;
|
||||||
|
unsigned int asyncDataSourceCollectionViewLockDataSource:1;
|
||||||
|
unsigned int asyncDataSourceCollectionViewUnlockDataSource:1;
|
||||||
|
unsigned int asyncDataSourceCollectionViewConstrainedSizeForNodeAtIndexPath:1;
|
||||||
|
} _asyncDataSourceFlags;
|
||||||
}
|
}
|
||||||
|
|
||||||
@property (atomic, assign) BOOL asyncDataSourceLocked;
|
@property (atomic, assign) BOOL asyncDataSourceLocked;
|
||||||
@ -333,16 +350,22 @@ static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell";
|
|||||||
if (asyncDataSource == nil) {
|
if (asyncDataSource == nil) {
|
||||||
_asyncDataSource = nil;
|
_asyncDataSource = nil;
|
||||||
_proxyDataSource = _isDeallocating ? nil : [[ASCollectionViewProxy alloc] initWithTarget:nil interceptor:self];
|
_proxyDataSource = _isDeallocating ? nil : [[ASCollectionViewProxy alloc] initWithTarget:nil interceptor:self];
|
||||||
_asyncDataSourceImplementsConstrainedSizeForNode = NO;
|
|
||||||
_asyncDataSourceImplementsNodeBlockForItemAtIndexPath = NO;
|
memset(&_asyncDataSourceFlags, 0, sizeof(_asyncDataSourceFlags));
|
||||||
} else {
|
} else {
|
||||||
_asyncDataSource = asyncDataSource;
|
_asyncDataSource = asyncDataSource;
|
||||||
_proxyDataSource = [[ASCollectionViewProxy alloc] initWithTarget:_asyncDataSource interceptor:self];
|
_proxyDataSource = [[ASCollectionViewProxy alloc] initWithTarget:_asyncDataSource interceptor:self];
|
||||||
_asyncDataSourceImplementsConstrainedSizeForNode = [_asyncDataSource respondsToSelector:@selector(collectionView:constrainedSizeForNodeAtIndexPath:)];
|
|
||||||
_asyncDataSourceImplementsNodeBlockForItemAtIndexPath = [_asyncDataSource respondsToSelector:@selector(collectionView:nodeBlockForItemAtIndexPath:)];
|
_asyncDataSourceFlags.asyncDataSourceConstrainedSizeForNode = [_asyncDataSource respondsToSelector:@selector(collectionView:constrainedSizeForNodeAtIndexPath:)];
|
||||||
|
_asyncDataSourceFlags.asyncDataSourceNodeForItemAtIndexPath = [_asyncDataSource respondsToSelector:@selector(collectionView:nodeForItemAtIndexPath:)];
|
||||||
|
_asyncDataSourceFlags.asyncDataSourceNodeBlockForItemAtIndexPath = [_asyncDataSource respondsToSelector:@selector(collectionView:nodeBlockForItemAtIndexPath:)];
|
||||||
|
_asyncDataSourceFlags.asyncDataSourceNumberOfSectionsInCollectionView = [_asyncDataSource respondsToSelector:@selector(numberOfSectionsInCollectionView:)];
|
||||||
|
_asyncDataSourceFlags.asyncDataSourceCollectionViewLockDataSource = [_asyncDataSource respondsToSelector:@selector(collectionViewLockDataSource:)];
|
||||||
|
_asyncDataSourceFlags.asyncDataSourceCollectionViewUnlockDataSource = [_asyncDataSource respondsToSelector:@selector(collectionViewUnlockDataSource:)];
|
||||||
|
_asyncDataSourceFlags.asyncDataSourceCollectionViewConstrainedSizeForNodeAtIndexPath = [_asyncDataSource respondsToSelector:@selector(collectionView:constrainedSizeForNodeAtIndexPath:)];;
|
||||||
|
|
||||||
// Data-source must implement collectionView:nodeForItemAtIndexPath: or collectionView:nodeBlockForItemAtIndexPath:
|
// Data-source must implement collectionView:nodeForItemAtIndexPath: or collectionView:nodeBlockForItemAtIndexPath:
|
||||||
ASDisplayNodeAssertTrue(_asyncDataSourceImplementsNodeBlockForItemAtIndexPath || [_asyncDataSource respondsToSelector:@selector(collectionView:nodeForItemAtIndexPath:)]);
|
ASDisplayNodeAssertTrue(_asyncDataSourceFlags.asyncDataSourceNodeBlockForItemAtIndexPath || _asyncDataSourceFlags.asyncDataSourceNodeForItemAtIndexPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
super.dataSource = (id<UICollectionViewDataSource>)_proxyDataSource;
|
super.dataSource = (id<UICollectionViewDataSource>)_proxyDataSource;
|
||||||
@ -363,11 +386,19 @@ static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell";
|
|||||||
if (asyncDelegate == nil) {
|
if (asyncDelegate == nil) {
|
||||||
_asyncDelegate = nil;
|
_asyncDelegate = nil;
|
||||||
_proxyDelegate = _isDeallocating ? nil : [[ASCollectionViewProxy alloc] initWithTarget:nil interceptor:self];
|
_proxyDelegate = _isDeallocating ? nil : [[ASCollectionViewProxy alloc] initWithTarget:nil interceptor:self];
|
||||||
_asyncDelegateImplementsScrollviewDidScroll = NO;
|
|
||||||
|
memset(&_asyncDelegateFlags, 0, sizeof(_asyncDelegateFlags));
|
||||||
} else {
|
} else {
|
||||||
_asyncDelegate = asyncDelegate;
|
_asyncDelegate = asyncDelegate;
|
||||||
_proxyDelegate = [[ASCollectionViewProxy alloc] initWithTarget:_asyncDelegate interceptor:self];
|
_proxyDelegate = [[ASCollectionViewProxy alloc] initWithTarget:_asyncDelegate interceptor:self];
|
||||||
_asyncDelegateImplementsScrollviewDidScroll = ([_asyncDelegate respondsToSelector:@selector(scrollViewDidScroll:)] ? 1 : 0);
|
|
||||||
|
_asyncDelegateFlags.asyncDelegateScrollViewDidScroll = [_asyncDelegate respondsToSelector:@selector(scrollViewDidScroll:)];
|
||||||
|
_asyncDelegateFlags.asyncDelegateScrollViewWillEndDraggingWithVelocityTargetContentOffset = [_asyncDelegate respondsToSelector:@selector(scrollViewWillEndDragging:withVelocity:targetContentOffset:)];
|
||||||
|
_asyncDelegateFlags.asyncDelegateCollectionViewWillDisplayNodeForItemAtIndexPath = [_asyncDelegate respondsToSelector:@selector(collectionView:willDisplayNodeForItemAtIndexPath:)];
|
||||||
|
_asyncDelegateFlags.asyncDelegateCollectionViewDidEndDisplayingNodeForItemAtIndexPathDeprecated = [_asyncDelegate respondsToSelector:@selector(collectionView:didEndDisplayingNodeForItemAtIndexPath:)];
|
||||||
|
_asyncDelegateFlags.asyncDelegateCollectionViewDidEndDisplayingNodeForItemAtIndexPath = [_asyncDelegate respondsToSelector:@selector(collectionView:didEndDisplayingNode:forItemAtIndexPath:)];
|
||||||
|
_asyncDelegateFlags.asyncDelegateCollectionViewWillBeginBatchFetchWithContext = [_asyncDelegate respondsToSelector:@selector(collectionView:willBeginBatchFetchWithContext:)];
|
||||||
|
_asyncDelegateFlags.asyncDelegateShouldBatchFetchForCollectionView = [_asyncDelegate respondsToSelector:@selector(shouldBatchFetchForCollectionView:)];
|
||||||
}
|
}
|
||||||
|
|
||||||
super.delegate = (id<UICollectionViewDelegate>)_proxyDelegate;
|
super.delegate = (id<UICollectionViewDelegate>)_proxyDelegate;
|
||||||
@ -566,7 +597,7 @@ static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell";
|
|||||||
ASCellNode *cellNode = [cell node];
|
ASCellNode *cellNode = [cell node];
|
||||||
cellNode.scrollView = collectionView;
|
cellNode.scrollView = collectionView;
|
||||||
|
|
||||||
if ([_asyncDelegate respondsToSelector:@selector(collectionView:willDisplayNodeForItemAtIndexPath:)]) {
|
if (_asyncDelegateFlags.asyncDelegateCollectionViewWillDisplayNodeForItemAtIndexPath) {
|
||||||
[_asyncDelegate collectionView:self willDisplayNodeForItemAtIndexPath:indexPath];
|
[_asyncDelegate collectionView:self willDisplayNodeForItemAtIndexPath:indexPath];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -586,7 +617,7 @@ static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell";
|
|||||||
|
|
||||||
ASCellNode *cellNode = [cell node];
|
ASCellNode *cellNode = [cell node];
|
||||||
|
|
||||||
if ([_asyncDelegate respondsToSelector:@selector(collectionView:didEndDisplayingNode:forItemAtIndexPath:)]) {
|
if (_asyncDelegateFlags.asyncDelegateCollectionViewDidEndDisplayingNodeForItemAtIndexPath) {
|
||||||
ASDisplayNodeAssertNotNil(cellNode, @"Expected node associated with removed cell not to be nil.");
|
ASDisplayNodeAssertNotNil(cellNode, @"Expected node associated with removed cell not to be nil.");
|
||||||
[_asyncDelegate collectionView:self didEndDisplayingNode:cellNode forItemAtIndexPath:indexPath];
|
[_asyncDelegate collectionView:self didEndDisplayingNode:cellNode forItemAtIndexPath:indexPath];
|
||||||
}
|
}
|
||||||
@ -597,7 +628,7 @@ static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell";
|
|||||||
|
|
||||||
#pragma clang diagnostic push
|
#pragma clang diagnostic push
|
||||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||||
if ([_asyncDelegate respondsToSelector:@selector(collectionView:didEndDisplayingNodeForItemAtIndexPath:)]) {
|
if (_asyncDelegateFlags.asyncDelegateCollectionViewDidEndDisplayingNodeForItemAtIndexPathDeprecated) {
|
||||||
[_asyncDelegate collectionView:self didEndDisplayingNodeForItemAtIndexPath:indexPath];
|
[_asyncDelegate collectionView:self didEndDisplayingNodeForItemAtIndexPath:indexPath];
|
||||||
}
|
}
|
||||||
#pragma clang diagnostic pop
|
#pragma clang diagnostic pop
|
||||||
@ -620,7 +651,7 @@ static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell";
|
|||||||
inScrollView:scrollView
|
inScrollView:scrollView
|
||||||
withCellFrame:collectionCell.frame];
|
withCellFrame:collectionCell.frame];
|
||||||
}
|
}
|
||||||
if (_asyncDelegateImplementsScrollviewDidScroll) {
|
if (_asyncDelegateFlags.asyncDelegateScrollViewDidScroll) {
|
||||||
[_asyncDelegate scrollViewDidScroll:scrollView];
|
[_asyncDelegate scrollViewDidScroll:scrollView];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -637,7 +668,7 @@ static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell";
|
|||||||
[self _beginBatchFetchingIfNeededWithScrollView:self forScrollDirection:[self scrollDirection] contentOffset:*targetContentOffset];
|
[self _beginBatchFetchingIfNeededWithScrollView:self forScrollDirection:[self scrollDirection] contentOffset:*targetContentOffset];
|
||||||
}
|
}
|
||||||
|
|
||||||
if ([_asyncDelegate respondsToSelector:@selector(scrollViewWillEndDragging:withVelocity:targetContentOffset:)]) {
|
if (_asyncDelegateFlags.asyncDelegateScrollViewWillEndDraggingWithVelocityTargetContentOffset) {
|
||||||
[_asyncDelegate scrollViewWillEndDragging:scrollView withVelocity:velocity targetContentOffset:targetContentOffset];
|
[_asyncDelegate scrollViewWillEndDragging:scrollView withVelocity:velocity targetContentOffset:targetContentOffset];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -747,8 +778,8 @@ static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell";
|
|||||||
- (BOOL)canBatchFetch
|
- (BOOL)canBatchFetch
|
||||||
{
|
{
|
||||||
// if the delegate does not respond to this method, there is no point in starting to fetch
|
// if the delegate does not respond to this method, there is no point in starting to fetch
|
||||||
BOOL canFetch = [_asyncDelegate respondsToSelector:@selector(collectionView:willBeginBatchFetchWithContext:)];
|
BOOL canFetch = _asyncDelegateFlags.asyncDelegateCollectionViewWillBeginBatchFetchWithContext;
|
||||||
if (canFetch && [_asyncDelegate respondsToSelector:@selector(shouldBatchFetchForCollectionView:)]) {
|
if (canFetch && _asyncDelegateFlags.asyncDelegateShouldBatchFetchForCollectionView) {
|
||||||
return [_asyncDelegate shouldBatchFetchForCollectionView:self];
|
return [_asyncDelegate shouldBatchFetchForCollectionView:self];
|
||||||
} else {
|
} else {
|
||||||
return canFetch;
|
return canFetch;
|
||||||
@ -788,7 +819,7 @@ static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell";
|
|||||||
- (void)_beginBatchFetching
|
- (void)_beginBatchFetching
|
||||||
{
|
{
|
||||||
[_batchContext beginBatchFetching];
|
[_batchContext beginBatchFetching];
|
||||||
if ([_asyncDelegate respondsToSelector:@selector(collectionView:willBeginBatchFetchWithContext:)]) {
|
if (_asyncDelegateFlags.asyncDelegateCollectionViewWillBeginBatchFetchWithContext) {
|
||||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||||
[_asyncDelegate collectionView:self willBeginBatchFetchWithContext:_batchContext];
|
[_asyncDelegate collectionView:self willBeginBatchFetchWithContext:_batchContext];
|
||||||
});
|
});
|
||||||
@ -800,7 +831,7 @@ static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell";
|
|||||||
|
|
||||||
- (ASCellNodeBlock)dataController:(ASDataController *)dataController nodeBlockAtIndexPath:(NSIndexPath *)indexPath
|
- (ASCellNodeBlock)dataController:(ASDataController *)dataController nodeBlockAtIndexPath:(NSIndexPath *)indexPath
|
||||||
{
|
{
|
||||||
if (!_asyncDataSourceImplementsNodeBlockForItemAtIndexPath) {
|
if (!_asyncDataSourceFlags.asyncDataSourceNodeBlockForItemAtIndexPath) {
|
||||||
ASCellNode *node = [_asyncDataSource collectionView:self nodeForItemAtIndexPath:indexPath];
|
ASCellNode *node = [_asyncDataSource collectionView:self nodeForItemAtIndexPath:indexPath];
|
||||||
ASDisplayNodeAssert([node isKindOfClass:ASCellNode.class], @"invalid node class, expected ASCellNode");
|
ASDisplayNodeAssert([node isKindOfClass:ASCellNode.class], @"invalid node class, expected ASCellNode");
|
||||||
__weak __typeof__(self) weakSelf = self;
|
__weak __typeof__(self) weakSelf = self;
|
||||||
@ -842,7 +873,7 @@ static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell";
|
|||||||
|
|
||||||
// TODO: Move this logic into the flow layout inspector. Create a simple inspector for non-flow layouts that don't
|
// TODO: Move this logic into the flow layout inspector. Create a simple inspector for non-flow layouts that don't
|
||||||
// implement a custom inspector.
|
// implement a custom inspector.
|
||||||
if (_asyncDataSourceImplementsConstrainedSizeForNode) {
|
if (_asyncDataSourceFlags.asyncDataSourceConstrainedSizeForNode) {
|
||||||
constrainedSize = [_asyncDataSource collectionView:self constrainedSizeForNodeAtIndexPath:indexPath];
|
constrainedSize = [_asyncDataSource collectionView:self constrainedSizeForNodeAtIndexPath:indexPath];
|
||||||
} else {
|
} else {
|
||||||
CGSize maxSize = CGSizeEqualToSize(_maxSizeForNodesConstrainedSize, CGSizeZero) ? self.bounds.size : _maxSizeForNodesConstrainedSize;
|
CGSize maxSize = CGSizeEqualToSize(_maxSizeForNodesConstrainedSize, CGSizeZero) ? self.bounds.size : _maxSizeForNodesConstrainedSize;
|
||||||
@ -863,7 +894,7 @@ static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell";
|
|||||||
}
|
}
|
||||||
|
|
||||||
- (NSUInteger)numberOfSectionsInDataController:(ASDataController *)dataController {
|
- (NSUInteger)numberOfSectionsInDataController:(ASDataController *)dataController {
|
||||||
if ([_asyncDataSource respondsToSelector:@selector(numberOfSectionsInCollectionView:)]) {
|
if (_asyncDataSourceFlags.asyncDataSourceNumberOfSectionsInCollectionView) {
|
||||||
return [_asyncDataSource numberOfSectionsInCollectionView:self];
|
return [_asyncDataSource numberOfSectionsInCollectionView:self];
|
||||||
} else {
|
} else {
|
||||||
return 1;
|
return 1;
|
||||||
@ -875,7 +906,7 @@ static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell";
|
|||||||
ASDisplayNodeAssert(!self.asyncDataSourceLocked, @"The data source has already been locked");
|
ASDisplayNodeAssert(!self.asyncDataSourceLocked, @"The data source has already been locked");
|
||||||
|
|
||||||
self.asyncDataSourceLocked = YES;
|
self.asyncDataSourceLocked = YES;
|
||||||
if ([_asyncDataSource respondsToSelector:@selector(collectionViewLockDataSource:)]) {
|
if (_asyncDataSourceFlags.asyncDataSourceCollectionViewLockDataSource) {
|
||||||
[_asyncDataSource collectionViewLockDataSource:self];
|
[_asyncDataSource collectionViewLockDataSource:self];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -885,7 +916,7 @@ static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell";
|
|||||||
ASDisplayNodeAssert(self.asyncDataSourceLocked, @"The data source has already been unlocked");
|
ASDisplayNodeAssert(self.asyncDataSourceLocked, @"The data source has already been unlocked");
|
||||||
|
|
||||||
self.asyncDataSourceLocked = NO;
|
self.asyncDataSourceLocked = NO;
|
||||||
if ([_asyncDataSource respondsToSelector:@selector(collectionViewUnlockDataSource:)]) {
|
if (_asyncDataSourceFlags.asyncDataSourceCollectionViewUnlockDataSource) {
|
||||||
[_asyncDataSource collectionViewUnlockDataSource:self];
|
[_asyncDataSource collectionViewUnlockDataSource:self];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1002,13 +1033,12 @@ static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell";
|
|||||||
return; // if the asyncDataSource has become invalid while we are processing, ignore this request to avoid crashes
|
return; // if the asyncDataSource has become invalid while we are processing, ignore this request to avoid crashes
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[_layoutFacilitator collectionViewWillEditCellsAtIndexPaths:indexPaths batched:_performingBatchUpdates];
|
||||||
if (_performingBatchUpdates) {
|
if (_performingBatchUpdates) {
|
||||||
[_layoutFacilitator collectionViewWillEditCellsAtIndexPaths:indexPaths batched:YES];
|
|
||||||
[_batchUpdateBlocks addObject:^{
|
[_batchUpdateBlocks addObject:^{
|
||||||
[super insertItemsAtIndexPaths:indexPaths];
|
[super insertItemsAtIndexPaths:indexPaths];
|
||||||
}];
|
}];
|
||||||
} else {
|
} else {
|
||||||
[_layoutFacilitator collectionViewWillEditCellsAtIndexPaths:indexPaths batched:NO];
|
|
||||||
[UIView performWithoutAnimation:^{
|
[UIView performWithoutAnimation:^{
|
||||||
[super insertItemsAtIndexPaths:indexPaths];
|
[super insertItemsAtIndexPaths:indexPaths];
|
||||||
[self _scheduleCheckForBatchFetchingForNumberOfChanges:indexPaths.count];
|
[self _scheduleCheckForBatchFetchingForNumberOfChanges:indexPaths.count];
|
||||||
@ -1023,13 +1053,12 @@ static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell";
|
|||||||
return; // if the asyncDataSource has become invalid while we are processing, ignore this request to avoid crashes
|
return; // if the asyncDataSource has become invalid while we are processing, ignore this request to avoid crashes
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[_layoutFacilitator collectionViewWillEditCellsAtIndexPaths:indexPaths batched:_performingBatchUpdates];
|
||||||
if (_performingBatchUpdates) {
|
if (_performingBatchUpdates) {
|
||||||
[_layoutFacilitator collectionViewWillEditCellsAtIndexPaths:indexPaths batched:YES];
|
|
||||||
[_batchUpdateBlocks addObject:^{
|
[_batchUpdateBlocks addObject:^{
|
||||||
[super deleteItemsAtIndexPaths:indexPaths];
|
[super deleteItemsAtIndexPaths:indexPaths];
|
||||||
}];
|
}];
|
||||||
} else {
|
} else {
|
||||||
[_layoutFacilitator collectionViewWillEditCellsAtIndexPaths:indexPaths batched:NO];
|
|
||||||
[UIView performWithoutAnimation:^{
|
[UIView performWithoutAnimation:^{
|
||||||
[super deleteItemsAtIndexPaths:indexPaths];
|
[super deleteItemsAtIndexPaths:indexPaths];
|
||||||
[self _scheduleCheckForBatchFetchingForNumberOfChanges:indexPaths.count];
|
[self _scheduleCheckForBatchFetchingForNumberOfChanges:indexPaths.count];
|
||||||
@ -1044,13 +1073,12 @@ static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell";
|
|||||||
return; // if the asyncDataSource has become invalid while we are processing, ignore this request to avoid crashes
|
return; // if the asyncDataSource has become invalid while we are processing, ignore this request to avoid crashes
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[_layoutFacilitator collectionViewWillEditSectionsAtIndexSet:indexSet batched:_performingBatchUpdates];
|
||||||
if (_performingBatchUpdates) {
|
if (_performingBatchUpdates) {
|
||||||
[_layoutFacilitator collectionViewWillEditSectionsAtIndexSet:indexSet batched:YES];
|
|
||||||
[_batchUpdateBlocks addObject:^{
|
[_batchUpdateBlocks addObject:^{
|
||||||
[super insertSections:indexSet];
|
[super insertSections:indexSet];
|
||||||
}];
|
}];
|
||||||
} else {
|
} else {
|
||||||
[_layoutFacilitator collectionViewWillEditSectionsAtIndexSet:indexSet batched:NO];
|
|
||||||
[UIView performWithoutAnimation:^{
|
[UIView performWithoutAnimation:^{
|
||||||
[super insertSections:indexSet];
|
[super insertSections:indexSet];
|
||||||
[self _scheduleCheckForBatchFetchingForNumberOfChanges:indexSet.count];
|
[self _scheduleCheckForBatchFetchingForNumberOfChanges:indexSet.count];
|
||||||
@ -1065,13 +1093,12 @@ static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell";
|
|||||||
return; // if the asyncDataSource has become invalid while we are processing, ignore this request to avoid crashes
|
return; // if the asyncDataSource has become invalid while we are processing, ignore this request to avoid crashes
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[_layoutFacilitator collectionViewWillEditSectionsAtIndexSet:indexSet batched:_performingBatchUpdates];
|
||||||
if (_performingBatchUpdates) {
|
if (_performingBatchUpdates) {
|
||||||
[_layoutFacilitator collectionViewWillEditSectionsAtIndexSet:indexSet batched:YES];
|
|
||||||
[_batchUpdateBlocks addObject:^{
|
[_batchUpdateBlocks addObject:^{
|
||||||
[super deleteSections:indexSet];
|
[super deleteSections:indexSet];
|
||||||
}];
|
}];
|
||||||
} else {
|
} else {
|
||||||
[_layoutFacilitator collectionViewWillEditSectionsAtIndexSet:indexSet batched:NO];
|
|
||||||
[UIView performWithoutAnimation:^{
|
[UIView performWithoutAnimation:^{
|
||||||
[super deleteSections:indexSet];
|
[super deleteSections:indexSet];
|
||||||
[self _scheduleCheckForBatchFetchingForNumberOfChanges:indexSet.count];
|
[self _scheduleCheckForBatchFetchingForNumberOfChanges:indexSet.count];
|
||||||
|
|||||||
@ -112,9 +112,25 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell";
|
|||||||
BOOL _ignoreNodesConstrainedWidthChange;
|
BOOL _ignoreNodesConstrainedWidthChange;
|
||||||
BOOL _queuedNodeHeightUpdate;
|
BOOL _queuedNodeHeightUpdate;
|
||||||
BOOL _isDeallocating;
|
BOOL _isDeallocating;
|
||||||
BOOL _dataSourceImplementsNodeBlockForRowAtIndexPath;
|
|
||||||
BOOL _asyncDelegateImplementsScrollviewDidScroll;
|
|
||||||
NSMutableSet *_cellsForVisibilityUpdates;
|
NSMutableSet *_cellsForVisibilityUpdates;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
unsigned int asyncDelegateScrollViewDidScroll:1;
|
||||||
|
unsigned int asyncDelegateTableViewWillDisplayNodeForRowAtIndexPath:1;
|
||||||
|
unsigned int asyncDelegateTableViewDidEndDisplayingNodeForRowAtIndexPath:1;
|
||||||
|
unsigned int asyncDelegateTableViewDidEndDisplayingNodeForRowAtIndexPathDeprecated:1;
|
||||||
|
unsigned int asyncDelegateScrollViewWillEndDraggingWithVelocityTargetContentOffset:1;
|
||||||
|
unsigned int asyncDelegateTableViewWillBeginBatchFetchWithContext:1;
|
||||||
|
unsigned int asyncDelegateShouldBatchFetchForTableView:1;
|
||||||
|
} _asyncDelegateFlags;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
unsigned int asyncDataSourceNumberOfSectionsInTableView:1;
|
||||||
|
unsigned int asyncDataSourceTableViewNodeBlockForRowAtIndexPath:1;
|
||||||
|
unsigned int asyncDataSourceTableViewNodeForRowAtIndexPath:1;
|
||||||
|
unsigned int asyncDataSourceTableViewLockDataSource:1;
|
||||||
|
unsigned int asyncDataSourceTableViewUnlockDataSource:1;
|
||||||
|
} _asyncDataSourceFlags;
|
||||||
}
|
}
|
||||||
|
|
||||||
@property (atomic, assign) BOOL asyncDataSourceLocked;
|
@property (atomic, assign) BOOL asyncDataSourceLocked;
|
||||||
@ -260,13 +276,20 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell";
|
|||||||
if (asyncDataSource == nil) {
|
if (asyncDataSource == nil) {
|
||||||
_asyncDataSource = nil;
|
_asyncDataSource = nil;
|
||||||
_proxyDataSource = _isDeallocating ? nil : [[ASTableViewProxy alloc] initWithTarget:nil interceptor:self];
|
_proxyDataSource = _isDeallocating ? nil : [[ASTableViewProxy alloc] initWithTarget:nil interceptor:self];
|
||||||
_dataSourceImplementsNodeBlockForRowAtIndexPath = NO;
|
|
||||||
|
memset(&_asyncDataSourceFlags, 0, sizeof(_asyncDataSourceFlags));
|
||||||
} else {
|
} else {
|
||||||
_asyncDataSource = asyncDataSource;
|
_asyncDataSource = asyncDataSource;
|
||||||
_dataSourceImplementsNodeBlockForRowAtIndexPath = [_asyncDataSource respondsToSelector:@selector(tableView:nodeBlockForRowAtIndexPath:)];
|
|
||||||
// Data source must implement tableView:nodeBlockForRowAtIndexPath: or tableView:nodeForRowAtIndexPath:
|
|
||||||
ASDisplayNodeAssertTrue(_dataSourceImplementsNodeBlockForRowAtIndexPath || [_asyncDataSource respondsToSelector:@selector(tableView:nodeForRowAtIndexPath:)]);
|
|
||||||
_proxyDataSource = [[ASTableViewProxy alloc] initWithTarget:_asyncDataSource interceptor:self];
|
_proxyDataSource = [[ASTableViewProxy alloc] initWithTarget:_asyncDataSource interceptor:self];
|
||||||
|
|
||||||
|
_asyncDataSourceFlags.asyncDataSourceNumberOfSectionsInTableView = [_asyncDataSource respondsToSelector:@selector(numberOfSectionsInTableView:)];
|
||||||
|
_asyncDataSourceFlags.asyncDataSourceTableViewNodeForRowAtIndexPath = [_asyncDataSource respondsToSelector:@selector(tableView:nodeForRowAtIndexPath:)];
|
||||||
|
_asyncDataSourceFlags.asyncDataSourceTableViewNodeBlockForRowAtIndexPath = [_asyncDataSource respondsToSelector:@selector(tableView:nodeBlockForRowAtIndexPath:)];
|
||||||
|
_asyncDataSourceFlags.asyncDataSourceTableViewLockDataSource = [_asyncDataSource respondsToSelector:@selector(tableViewLockDataSource:)];
|
||||||
|
_asyncDataSourceFlags.asyncDataSourceTableViewUnlockDataSource = [_asyncDataSource respondsToSelector:@selector(tableViewUnlockDataSource:)];
|
||||||
|
|
||||||
|
// Data source must implement tableView:nodeBlockForRowAtIndexPath: or tableView:nodeForRowAtIndexPath:
|
||||||
|
ASDisplayNodeAssertTrue(_asyncDataSourceFlags.asyncDataSourceTableViewNodeBlockForRowAtIndexPath || _asyncDataSourceFlags.asyncDataSourceTableViewNodeForRowAtIndexPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
super.dataSource = (id<UITableViewDataSource>)_proxyDataSource;
|
super.dataSource = (id<UITableViewDataSource>)_proxyDataSource;
|
||||||
@ -287,11 +310,19 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell";
|
|||||||
if (asyncDelegate == nil) {
|
if (asyncDelegate == nil) {
|
||||||
_asyncDelegate = nil;
|
_asyncDelegate = nil;
|
||||||
_proxyDelegate = _isDeallocating ? nil : [[ASTableViewProxy alloc] initWithTarget:nil interceptor:self];
|
_proxyDelegate = _isDeallocating ? nil : [[ASTableViewProxy alloc] initWithTarget:nil interceptor:self];
|
||||||
_asyncDelegateImplementsScrollviewDidScroll = NO;
|
|
||||||
|
memset(&_asyncDelegateFlags, 0, sizeof(_asyncDelegateFlags));
|
||||||
} else {
|
} else {
|
||||||
_asyncDelegate = asyncDelegate;
|
_asyncDelegate = asyncDelegate;
|
||||||
_asyncDelegateImplementsScrollviewDidScroll = [_asyncDelegate respondsToSelector:@selector(scrollViewDidScroll:)];
|
|
||||||
_proxyDelegate = [[ASTableViewProxy alloc] initWithTarget:_asyncDelegate interceptor:self];
|
_proxyDelegate = [[ASTableViewProxy alloc] initWithTarget:_asyncDelegate interceptor:self];
|
||||||
|
|
||||||
|
_asyncDelegateFlags.asyncDelegateScrollViewDidScroll = [_asyncDelegate respondsToSelector:@selector(scrollViewDidScroll:)];
|
||||||
|
_asyncDelegateFlags.asyncDelegateTableViewWillDisplayNodeForRowAtIndexPath = [_asyncDelegate respondsToSelector:@selector(tableView:willDisplayNodeForRowAtIndexPath:)];
|
||||||
|
_asyncDelegateFlags.asyncDelegateTableViewDidEndDisplayingNodeForRowAtIndexPath = [_asyncDelegate respondsToSelector:@selector(tableView:didEndDisplayingNode:forRowAtIndexPath:)];
|
||||||
|
_asyncDelegateFlags.asyncDelegateTableViewDidEndDisplayingNodeForRowAtIndexPathDeprecated = [_asyncDelegate respondsToSelector:@selector(tableView:didEndDisplayingNodeForRowAtIndexPath:)];
|
||||||
|
_asyncDelegateFlags.asyncDelegateScrollViewWillEndDraggingWithVelocityTargetContentOffset = [_asyncDelegate respondsToSelector:@selector(scrollViewWillEndDragging:withVelocity:targetContentOffset:)];
|
||||||
|
_asyncDelegateFlags.asyncDelegateTableViewWillBeginBatchFetchWithContext = [_asyncDelegate respondsToSelector:@selector(tableView:willBeginBatchFetchWithContext:)];
|
||||||
|
_asyncDelegateFlags.asyncDelegateShouldBatchFetchForTableView = [_asyncDelegate respondsToSelector:@selector(shouldBatchFetchForTableView:)];
|
||||||
}
|
}
|
||||||
|
|
||||||
super.delegate = (id<UITableViewDelegate>)_proxyDelegate;
|
super.delegate = (id<UITableViewDelegate>)_proxyDelegate;
|
||||||
@ -584,7 +615,7 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell";
|
|||||||
ASCellNode *cellNode = [cell node];
|
ASCellNode *cellNode = [cell node];
|
||||||
cellNode.scrollView = tableView;
|
cellNode.scrollView = tableView;
|
||||||
|
|
||||||
if ([_asyncDelegate respondsToSelector:@selector(tableView:willDisplayNodeForRowAtIndexPath:)]) {
|
if (_asyncDelegateFlags.asyncDelegateTableViewWillDisplayNodeForRowAtIndexPath) {
|
||||||
[_asyncDelegate tableView:self willDisplayNodeForRowAtIndexPath:indexPath];
|
[_asyncDelegate tableView:self willDisplayNodeForRowAtIndexPath:indexPath];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -609,7 +640,7 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell";
|
|||||||
|
|
||||||
[_rangeController visibleNodeIndexPathsDidChangeWithScrollDirection:[self scrollDirection]];
|
[_rangeController visibleNodeIndexPathsDidChangeWithScrollDirection:[self scrollDirection]];
|
||||||
|
|
||||||
if ([_asyncDelegate respondsToSelector:@selector(tableView:didEndDisplayingNode:forRowAtIndexPath:)]) {
|
if (_asyncDelegateFlags.asyncDelegateTableViewDidEndDisplayingNodeForRowAtIndexPath) {
|
||||||
ASDisplayNodeAssertNotNil(cellNode, @"Expected node associated with removed cell not to be nil.");
|
ASDisplayNodeAssertNotNil(cellNode, @"Expected node associated with removed cell not to be nil.");
|
||||||
[_asyncDelegate tableView:self didEndDisplayingNode:cellNode forRowAtIndexPath:indexPath];
|
[_asyncDelegate tableView:self didEndDisplayingNode:cellNode forRowAtIndexPath:indexPath];
|
||||||
}
|
}
|
||||||
@ -620,7 +651,7 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell";
|
|||||||
|
|
||||||
#pragma clang diagnostic push
|
#pragma clang diagnostic push
|
||||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||||
if ([_asyncDelegate respondsToSelector:@selector(tableView:didEndDisplayingNodeForRowAtIndexPath:)]) {
|
if (_asyncDelegateFlags.asyncDelegateTableViewDidEndDisplayingNodeForRowAtIndexPathDeprecated) {
|
||||||
[_asyncDelegate tableView:self didEndDisplayingNodeForRowAtIndexPath:indexPath];
|
[_asyncDelegate tableView:self didEndDisplayingNodeForRowAtIndexPath:indexPath];
|
||||||
}
|
}
|
||||||
#pragma clang diagnostic pop
|
#pragma clang diagnostic pop
|
||||||
@ -642,7 +673,7 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell";
|
|||||||
inScrollView:scrollView
|
inScrollView:scrollView
|
||||||
withCellFrame:tableCell.frame];
|
withCellFrame:tableCell.frame];
|
||||||
}
|
}
|
||||||
if (_asyncDelegateImplementsScrollviewDidScroll) {
|
if (_asyncDelegateFlags.asyncDelegateScrollViewDidScroll) {
|
||||||
[_asyncDelegate scrollViewDidScroll:scrollView];
|
[_asyncDelegate scrollViewDidScroll:scrollView];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -659,7 +690,7 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell";
|
|||||||
[self _beginBatchFetchingIfNeededWithScrollView:self forScrollDirection:[self scrollDirection] contentOffset:*targetContentOffset];
|
[self _beginBatchFetchingIfNeededWithScrollView:self forScrollDirection:[self scrollDirection] contentOffset:*targetContentOffset];
|
||||||
}
|
}
|
||||||
|
|
||||||
if ([_asyncDelegate respondsToSelector:@selector(scrollViewWillEndDragging:withVelocity:targetContentOffset:)]) {
|
if (_asyncDelegateFlags.asyncDelegateScrollViewWillEndDraggingWithVelocityTargetContentOffset) {
|
||||||
[_asyncDelegate scrollViewWillEndDragging:scrollView withVelocity:velocity targetContentOffset:targetContentOffset];
|
[_asyncDelegate scrollViewWillEndDragging:scrollView withVelocity:velocity targetContentOffset:targetContentOffset];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -722,8 +753,8 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell";
|
|||||||
- (BOOL)canBatchFetch
|
- (BOOL)canBatchFetch
|
||||||
{
|
{
|
||||||
// if the delegate does not respond to this method, there is no point in starting to fetch
|
// if the delegate does not respond to this method, there is no point in starting to fetch
|
||||||
BOOL canFetch = [_asyncDelegate respondsToSelector:@selector(tableView:willBeginBatchFetchWithContext:)];
|
BOOL canFetch = _asyncDelegateFlags.asyncDelegateTableViewWillBeginBatchFetchWithContext;
|
||||||
if (canFetch && [_asyncDelegate respondsToSelector:@selector(shouldBatchFetchForTableView:)]) {
|
if (canFetch && _asyncDelegateFlags.asyncDelegateShouldBatchFetchForTableView) {
|
||||||
return [_asyncDelegate shouldBatchFetchForTableView:self];
|
return [_asyncDelegate shouldBatchFetchForTableView:self];
|
||||||
} else {
|
} else {
|
||||||
return canFetch;
|
return canFetch;
|
||||||
@ -763,7 +794,7 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell";
|
|||||||
- (void)_beginBatchFetching
|
- (void)_beginBatchFetching
|
||||||
{
|
{
|
||||||
[_batchContext beginBatchFetching];
|
[_batchContext beginBatchFetching];
|
||||||
if ([_asyncDelegate respondsToSelector:@selector(tableView:willBeginBatchFetchWithContext:)]) {
|
if (_asyncDelegateFlags.asyncDelegateTableViewWillBeginBatchFetchWithContext) {
|
||||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||||
[_asyncDelegate tableView:self willBeginBatchFetchWithContext:_batchContext];
|
[_asyncDelegate tableView:self willBeginBatchFetchWithContext:_batchContext];
|
||||||
});
|
});
|
||||||
@ -1013,7 +1044,7 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell";
|
|||||||
|
|
||||||
self.asyncDataSourceLocked = YES;
|
self.asyncDataSourceLocked = YES;
|
||||||
|
|
||||||
if ([_asyncDataSource respondsToSelector:@selector(tableViewLockDataSource:)]) {
|
if (_asyncDataSourceFlags.asyncDataSourceTableViewLockDataSource) {
|
||||||
[_asyncDataSource tableViewLockDataSource:self];
|
[_asyncDataSource tableViewLockDataSource:self];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1024,7 +1055,7 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell";
|
|||||||
|
|
||||||
self.asyncDataSourceLocked = NO;
|
self.asyncDataSourceLocked = NO;
|
||||||
|
|
||||||
if ([_asyncDataSource respondsToSelector:@selector(tableViewUnlockDataSource:)]) {
|
if (_asyncDataSourceFlags.asyncDataSourceTableViewUnlockDataSource) {
|
||||||
[_asyncDataSource tableViewUnlockDataSource:self];
|
[_asyncDataSource tableViewUnlockDataSource:self];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1036,7 +1067,7 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell";
|
|||||||
|
|
||||||
- (NSUInteger)numberOfSectionsInDataController:(ASDataController *)dataController
|
- (NSUInteger)numberOfSectionsInDataController:(ASDataController *)dataController
|
||||||
{
|
{
|
||||||
if ([_asyncDataSource respondsToSelector:@selector(numberOfSectionsInTableView:)]) {
|
if (_asyncDataSourceFlags.asyncDataSourceNumberOfSectionsInTableView) {
|
||||||
return [_asyncDataSource numberOfSectionsInTableView:self];
|
return [_asyncDataSource numberOfSectionsInTableView:self];
|
||||||
} else {
|
} else {
|
||||||
return 1; // default section number
|
return 1; // default section number
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user