mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-10 08:20:16 +00:00
Ensure that ASRangeController immediately removes any deleted nodes from its range state.
This commit is contained in:
parent
9b9d8bc9b6
commit
ffcddf36e2
@ -927,4 +927,23 @@ static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell";
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - UICollectionView dead-end intercepts
|
||||
|
||||
#if ASDISPLAYNODE_ASSERTIONS_ENABLED // Remove implementations entirely for efficiency if not asserting.
|
||||
|
||||
// intercepted due to not being supported by ASCollectionView (prevent bugs caused by usage)
|
||||
|
||||
- (BOOL)collectionView:(UICollectionView *)collectionView canMoveItemAtIndexPath:(NSIndexPath *)indexPath NS_AVAILABLE_IOS(9_0)
|
||||
{
|
||||
ASDisplayNodeAssert(![self.asyncDataSource respondsToSelector:_cmd], @"%@ is not supported by ASCollectionView - please remove or disable this data source method.", NSStringFromSelector(_cmd));
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (void)collectionView:(UICollectionView *)collectionView moveItemAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath*)destinationIndexPath NS_AVAILABLE_IOS(9_0)
|
||||
{
|
||||
ASDisplayNodeAssert(![self.asyncDataSource respondsToSelector:_cmd], @"%@ is not supported by ASCollectionView - please remove or disable this data source method.", NSStringFromSelector(_cmd));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@end
|
||||
|
||||
@ -17,27 +17,24 @@
|
||||
- (ASCellNode *)pagerNode:(ASPagerNode *)pagerNode nodeAtIndex:(NSInteger)index;
|
||||
@end
|
||||
|
||||
// WARNING: ASPagerNode is new in AsyncDisplayKit 1.9.4 and not yet widely tested.
|
||||
// Details of its API or behavior may change in future releases
|
||||
@interface ASPagerNode : ASCollectionNode
|
||||
|
||||
// Configures a default horizontal, paging flow layout with 0 inter-item spacing.
|
||||
- (instancetype)init;
|
||||
|
||||
// Initializer with custom-configured flow layout properties.
|
||||
- (instancetype)initWithFlowLayout:(UICollectionViewFlowLayout *)flowLayout;
|
||||
- (instancetype)initWithCollectionViewLayout:(UICollectionViewFlowLayout *)flowLayout;
|
||||
|
||||
// The underlying ASCollectionView object.
|
||||
@property (nonatomic, readonly) ASCollectionView *view;
|
||||
// Data Source is required, and uses a different protocol from ASCollectionNode.
|
||||
- (void)setDataSource:(id <ASPagerNodeDataSource>)dataSource;
|
||||
- (id <ASPagerNodeDataSource>)dataSource;
|
||||
|
||||
// Delegate is optional, and uses the same protocol as ASCollectionNode.
|
||||
// This includes UIScrollViewDelegate as well as most methods from UICollectionViewDelegate, like willDisplay...
|
||||
@property (nonatomic, weak) id <ASCollectionDelegate> delegate;
|
||||
|
||||
// Data Source is required, and uses a different protocol from ASCollectionNode.
|
||||
//@property (nonatomic, weak) id <ASPagerNodeDataSource> dataSource;
|
||||
- (void)setDataSource:(id <ASPagerNodeDataSource>)dataSource;
|
||||
- (id <ASPagerNodeDataSource>)dataSource;
|
||||
// The underlying ASCollectionView object.
|
||||
@property (nonatomic, readonly) ASCollectionView *view;
|
||||
|
||||
- (void)scrollToPageAtIndex:(NSInteger)index animated:(BOOL)animated;
|
||||
|
||||
|
||||
@ -29,17 +29,12 @@
|
||||
flowLayout.minimumInteritemSpacing = 0;
|
||||
flowLayout.minimumLineSpacing = 0;
|
||||
|
||||
return [self initWithFlowLayout:flowLayout];
|
||||
return [self initWithCollectionViewLayout:flowLayout];
|
||||
}
|
||||
|
||||
- (instancetype)initWithCollectionViewLayout:(UICollectionViewLayout *)layout
|
||||
{
|
||||
ASDisplayNodeAssert([layout isKindOfClass:[UICollectionViewFlowLayout class]], @"ASPagerNode requires a flow layout.");
|
||||
return [self initWithFlowLayout:(UICollectionViewFlowLayout *)layout];
|
||||
}
|
||||
|
||||
- (instancetype)initWithFlowLayout:(UICollectionViewFlowLayout *)flowLayout
|
||||
- (instancetype)initWithCollectionViewLayout:(UICollectionViewFlowLayout *)flowLayout;
|
||||
{
|
||||
ASDisplayNodeAssert([flowLayout isKindOfClass:[UICollectionViewFlowLayout class]], @"ASPagerNode requires a flow layout.");
|
||||
self = [super initWithCollectionViewLayout:flowLayout];
|
||||
if (self != nil) {
|
||||
_flowLayout = flowLayout;
|
||||
|
||||
@ -9,7 +9,7 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@class ASDelegateProxy;
|
||||
@protocol ASDelegateProxyInterceptor
|
||||
@protocol ASDelegateProxyInterceptor <NSObject>
|
||||
@required
|
||||
// Called if the target object is discovered to be nil if it had been non-nil at init time.
|
||||
// This happens if the object is deallocated, because the proxy must maintain a weak reference to avoid cycles.
|
||||
@ -25,7 +25,7 @@
|
||||
|
||||
@interface ASDelegateProxy : NSProxy
|
||||
|
||||
- (instancetype)initWithTarget:(id<NSObject>)target interceptor:(id <ASDelegateProxyInterceptor>)interceptor;
|
||||
- (instancetype)initWithTarget:(id <NSObject>)target interceptor:(id <ASDelegateProxyInterceptor>)interceptor;
|
||||
|
||||
// This method must be overridden by a subclass.
|
||||
- (BOOL)interceptsSelector:(SEL)selector;
|
||||
|
||||
@ -54,7 +54,11 @@
|
||||
selector == @selector(collectionView:didEndDisplayingCell:forItemAtIndexPath:) ||
|
||||
|
||||
// used for batch fetching API
|
||||
selector == @selector(scrollViewWillEndDragging:withVelocity:targetContentOffset:)
|
||||
selector == @selector(scrollViewWillEndDragging:withVelocity:targetContentOffset:) ||
|
||||
|
||||
// intercepted due to not being supported by ASCollectionView (prevent bugs caused by usage)
|
||||
selector == @selector(collectionView:canMoveItemAtIndexPath:) ||
|
||||
selector == @selector(collectionView:moveItemAtIndexPath:toIndexPath:)
|
||||
);
|
||||
}
|
||||
|
||||
@ -97,7 +101,7 @@
|
||||
- (BOOL)respondsToSelector:(SEL)aSelector
|
||||
{
|
||||
if ([self interceptsSelector:aSelector]) {
|
||||
return (_interceptor != nil);
|
||||
return [_interceptor respondsToSelector:aSelector];
|
||||
} else {
|
||||
// Also return NO if _target has become nil due to zeroing weak reference (or placeholder initialization).
|
||||
return [_target respondsToSelector:aSelector];
|
||||
|
||||
@ -9,7 +9,7 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
typedef NS_ENUM(NSInteger, ASLayoutRangeType) {
|
||||
ASLayoutRangeTypeVisible,
|
||||
ASLayoutRangeTypeVisible = 0,
|
||||
ASLayoutRangeTypeRender,
|
||||
ASLayoutRangeTypePreload,
|
||||
ASLayoutRangeTypeCount
|
||||
|
||||
@ -130,7 +130,8 @@
|
||||
rangeType:rangeType];
|
||||
|
||||
// Notify to remove indexpaths that are leftover that are not visible or included in the _layoutController calculated paths
|
||||
NSMutableSet *removedIndexPaths = _rangeIsValid ? [_rangeTypeIndexPaths[rangeKey] mutableCopy] : [NSMutableSet set];
|
||||
// This value may be nil for the first call of this method.
|
||||
NSMutableSet *removedIndexPaths = [_rangeTypeIndexPaths[rangeKey] mutableCopy];
|
||||
[removedIndexPaths minusSet:indexPaths];
|
||||
[removedIndexPaths minusSet:visibleNodePathsSet];
|
||||
|
||||
@ -176,61 +177,76 @@
|
||||
|
||||
#pragma mark - ASDataControllerDelegete
|
||||
|
||||
- (void)dataControllerBeginUpdates:(ASDataController *)dataController {
|
||||
- (void)dataControllerBeginUpdates:(ASDataController *)dataController
|
||||
{
|
||||
ASPerformBlockOnMainThread(^{
|
||||
[_delegate didBeginUpdatesInRangeController:self];
|
||||
});
|
||||
}
|
||||
|
||||
- (void)dataController:(ASDataController *)dataController endUpdatesAnimated:(BOOL)animated completion:(void (^)(BOOL))completion {
|
||||
- (void)dataController:(ASDataController *)dataController endUpdatesAnimated:(BOOL)animated completion:(void (^)(BOOL))completion
|
||||
{
|
||||
ASPerformBlockOnMainThread(^{
|
||||
[_delegate rangeController:self didEndUpdatesAnimated:animated completion:completion];
|
||||
});
|
||||
}
|
||||
|
||||
- (void)dataController:(ASDataController *)dataController didInsertNodes:(NSArray *)nodes atIndexPaths:(NSArray *)indexPaths withAnimationOptions:(ASDataControllerAnimationOptions)animationOptions {
|
||||
- (void)dataController:(ASDataController *)dataController didInsertNodes:(NSArray *)nodes atIndexPaths:(NSArray *)indexPaths withAnimationOptions:(ASDataControllerAnimationOptions)animationOptions
|
||||
{
|
||||
ASDisplayNodeAssert(nodes.count == indexPaths.count, @"Invalid index path");
|
||||
|
||||
NSMutableArray *nodeSizes = [NSMutableArray arrayWithCapacity:nodes.count];
|
||||
[nodes enumerateObjectsUsingBlock:^(ASCellNode *node, NSUInteger idx, BOOL *stop) {
|
||||
[nodeSizes addObject:[NSValue valueWithCGSize:node.calculatedSize]];
|
||||
}];
|
||||
|
||||
ASPerformBlockOnMainThread(^{
|
||||
_rangeIsValid = NO;
|
||||
[_delegate rangeController:self didInsertNodes:nodes atIndexPaths:indexPaths withAnimationOptions:animationOptions];
|
||||
});
|
||||
}
|
||||
|
||||
- (void)dataController:(ASDataController *)dataController didDeleteNodes:(NSArray *)nodes atIndexPaths:(NSArray *)indexPaths withAnimationOptions:(ASDataControllerAnimationOptions)animationOptions {
|
||||
- (void)dataController:(ASDataController *)dataController didDeleteNodes:(NSArray *)nodes atIndexPaths:(NSArray *)indexPaths withAnimationOptions:(ASDataControllerAnimationOptions)animationOptions
|
||||
{
|
||||
ASPerformBlockOnMainThread(^{
|
||||
_rangeIsValid = NO;
|
||||
|
||||
// When removing nodes we need to make sure that removed indexPaths are not left in _rangeTypeIndexPaths,
|
||||
// otherwise _updateVisibleNodeIndexPaths may try to retrieve nodes from dataSource that aren't there anymore
|
||||
for (NSInteger i = 0; i < ASLayoutRangeTypeCount; i++) {
|
||||
id rangeKey = @((ASLayoutRangeType)i);
|
||||
NSMutableSet *rangePaths = [_rangeTypeIndexPaths[rangeKey] mutableCopy];
|
||||
for (NSIndexPath *path in indexPaths) {
|
||||
[rangePaths removeObject:path];
|
||||
}
|
||||
_rangeTypeIndexPaths[rangeKey] = rangePaths;
|
||||
}
|
||||
|
||||
[_delegate rangeController:self didDeleteNodes:nodes atIndexPaths:indexPaths withAnimationOptions:animationOptions];
|
||||
});
|
||||
}
|
||||
|
||||
- (void)dataController:(ASDataController *)dataController didInsertSections:(NSArray *)sections atIndexSet:(NSIndexSet *)indexSet withAnimationOptions:(ASDataControllerAnimationOptions)animationOptions {
|
||||
- (void)dataController:(ASDataController *)dataController didInsertSections:(NSArray *)sections atIndexSet:(NSIndexSet *)indexSet withAnimationOptions:(ASDataControllerAnimationOptions)animationOptions
|
||||
{
|
||||
ASDisplayNodeAssert(sections.count == indexSet.count, @"Invalid sections");
|
||||
|
||||
NSMutableArray *sectionNodeSizes = [NSMutableArray arrayWithCapacity:sections.count];
|
||||
|
||||
[sections enumerateObjectsUsingBlock:^(NSArray *nodes, NSUInteger idx, BOOL *stop) {
|
||||
NSMutableArray *nodeSizes = [NSMutableArray arrayWithCapacity:nodes.count];
|
||||
[nodes enumerateObjectsUsingBlock:^(ASCellNode *node, NSUInteger idx2, BOOL *stop2) {
|
||||
[nodeSizes addObject:[NSValue valueWithCGSize:node.calculatedSize]];
|
||||
}];
|
||||
[sectionNodeSizes addObject:nodeSizes];
|
||||
}];
|
||||
|
||||
ASPerformBlockOnMainThread(^{
|
||||
_rangeIsValid = NO;
|
||||
[_delegate rangeController:self didInsertSectionsAtIndexSet:indexSet withAnimationOptions:animationOptions];
|
||||
});
|
||||
}
|
||||
|
||||
- (void)dataController:(ASDataController *)dataController didDeleteSectionsAtIndexSet:(NSIndexSet *)indexSet withAnimationOptions:(ASDataControllerAnimationOptions)animationOptions {
|
||||
- (void)dataController:(ASDataController *)dataController didDeleteSectionsAtIndexSet:(NSIndexSet *)indexSet withAnimationOptions:(ASDataControllerAnimationOptions)animationOptions
|
||||
{
|
||||
ASPerformBlockOnMainThread(^{
|
||||
_rangeIsValid = NO;
|
||||
|
||||
// When removing nodes we need to make sure that removed indexPaths are not left in _rangeTypeIndexPaths,
|
||||
// otherwise _updateVisibleNodeIndexPaths may try to retrieve nodes from dataSource that aren't there anymore
|
||||
for (NSInteger i = 0; i < ASLayoutRangeTypeCount; i++) {
|
||||
id rangeKey = @((ASLayoutRangeType)i);
|
||||
NSMutableSet *rangePaths = [_rangeTypeIndexPaths[rangeKey] mutableCopy];
|
||||
for (NSIndexPath *path in _rangeTypeIndexPaths[rangeKey]) {
|
||||
if ([indexSet containsIndex:path.section]) {
|
||||
[rangePaths removeObject:path];
|
||||
}
|
||||
}
|
||||
_rangeTypeIndexPaths[rangeKey] = rangePaths;
|
||||
}
|
||||
|
||||
[_delegate rangeController:self didDeleteSectionsAtIndexSet:indexSet withAnimationOptions:animationOptions];
|
||||
});
|
||||
}
|
||||
|
||||
@ -19,4 +19,6 @@
|
||||
|
||||
- (instancetype)initWithElementSize:(CGSize)size;
|
||||
|
||||
@property (nonatomic) NSInteger pageNumber;
|
||||
|
||||
@end
|
||||
|
||||
@ -63,9 +63,16 @@
|
||||
{
|
||||
RandomCoreGraphicsNode *elementNode = [[RandomCoreGraphicsNode alloc] init];
|
||||
elementNode.preferredFrameSize = _elementSize;
|
||||
elementNode.indexPath = [NSIndexPath indexPathForRow:indexPath.row inSection:_pageNumber];
|
||||
return elementNode;
|
||||
}
|
||||
|
||||
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
[tableView deselectRowAtIndexPath:indexPath animated:NO];
|
||||
[_tableNode.view reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone];
|
||||
}
|
||||
|
||||
- (void)layout
|
||||
{
|
||||
[super layout];
|
||||
|
||||
@ -10,4 +10,6 @@
|
||||
|
||||
@interface RandomCoreGraphicsNode : ASCellNode
|
||||
|
||||
@property (nonatomic) NSIndexPath *indexPath;
|
||||
|
||||
@end
|
||||
|
||||
@ -42,4 +42,24 @@
|
||||
CGColorSpaceRelease(colorSpace);
|
||||
}
|
||||
|
||||
#if 0
|
||||
- (void)fetchData
|
||||
{
|
||||
NSLog(@"fetchData - %@, %@", self, self.indexPath);
|
||||
[super fetchData];
|
||||
}
|
||||
|
||||
- (void)clearFetchedData
|
||||
{
|
||||
NSLog(@"clearFetchedData - %@, %@", self, self.indexPath);
|
||||
[super clearFetchedData];
|
||||
}
|
||||
|
||||
- (void)visibilityDidChange:(BOOL)isVisible
|
||||
{
|
||||
NSLog(@"visibilityDidChange:%d - %@, %@", isVisible, self, self.indexPath);
|
||||
[super visibilityDidChange:isVisible];
|
||||
}
|
||||
#endif
|
||||
|
||||
@end
|
||||
|
||||
@ -69,12 +69,13 @@
|
||||
#pragma mark -
|
||||
#pragma mark ASPagerNode.
|
||||
|
||||
- (ASCellNode *)pagerNode:(ASPagerNode *)pagerNode nodeAtIndex:(NSInteger)index;
|
||||
- (ASCellNode *)pagerNode:(ASPagerNode *)pagerNode nodeAtIndex:(NSInteger)index
|
||||
{
|
||||
CGSize boundsSize = pagerNode.bounds.size;
|
||||
CGSize gradientRowSize = CGSizeMake(boundsSize.width, 100);
|
||||
GradientTableNode *node = [[GradientTableNode alloc] initWithElementSize:gradientRowSize];
|
||||
node.preferredFrameSize = boundsSize;
|
||||
node.pageNumber = index;
|
||||
return node;
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user