diff --git a/AsyncDisplayKit/ASDisplayNode.mm b/AsyncDisplayKit/ASDisplayNode.mm index 212c5c76f1..15f0cfcc34 100644 --- a/AsyncDisplayKit/ASDisplayNode.mm +++ b/AsyncDisplayKit/ASDisplayNode.mm @@ -1337,6 +1337,7 @@ static NSInteger incrementIfFound(NSInteger i) { { self.layer.contents = nil; _placeholderLayer.contents = nil; + _placeholderImage = nil; } - (void)recursivelyClearContents diff --git a/AsyncDisplayKit/ASTableView.mm b/AsyncDisplayKit/ASTableView.mm index 12fa595119..6473eab376 100644 --- a/AsyncDisplayKit/ASTableView.mm +++ b/AsyncDisplayKit/ASTableView.mm @@ -117,7 +117,7 @@ static BOOL _isInterceptedSelector(SEL sel) _ASTableViewProxy *_proxyDelegate; ASDataController *_dataController; - ASCollectionViewLayoutController *_layoutController; + ASFlowLayoutController *_layoutController; ASRangeController *_rangeController; @@ -159,9 +159,8 @@ void ASPerformBlockWithoutAnimation(BOOL withoutAnimation, void (^block)()) { - (void)configureWithAsyncDataFetching:(BOOL)asyncDataFetchingEnabled { - UICollectionViewFlowLayout *flowLayout = [[UICollectionViewFlowLayout alloc] init]; - _layoutController = [[ASCollectionViewLayoutController alloc] initWithScrollView:self collectionViewLayout:flowLayout]; - + _layoutController = [[ASFlowLayoutController alloc] initWithScrollOption:ASFlowLayoutDirectionVertical]; + _rangeController = [[ASRangeController alloc] init]; _rangeController.layoutController = _layoutController; _rangeController.delegate = self; @@ -169,6 +168,8 @@ void ASPerformBlockWithoutAnimation(BOOL withoutAnimation, void (^block)()) { _dataController = [[ASDataController alloc] initWithAsyncDataFetching:asyncDataFetchingEnabled]; _dataController.dataSource = self; _dataController.delegate = _rangeController; + + _layoutController.dataSource = _dataController; _asyncDataFetchingEnabled = asyncDataFetchingEnabled; _asyncDataSourceLocked = NO; diff --git a/AsyncDisplayKit/Details/ASCollectionViewLayoutController.h b/AsyncDisplayKit/Details/ASCollectionViewLayoutController.h index 3c33ae189a..9aa25db0a9 100644 --- a/AsyncDisplayKit/Details/ASCollectionViewLayoutController.h +++ b/AsyncDisplayKit/Details/ASCollectionViewLayoutController.h @@ -14,6 +14,5 @@ @interface ASCollectionViewLayoutController : ASAbstractLayoutController - (instancetype)initWithCollectionView:(ASCollectionView *)collectionView; -- (instancetype)initWithScrollView:(UIScrollView *)scrollView collectionViewLayout:(UICollectionViewLayout *)layout; @end diff --git a/AsyncDisplayKit/Details/ASCollectionViewLayoutController.mm b/AsyncDisplayKit/Details/ASCollectionViewLayoutController.mm index c83a0ac2bd..8655102738 100644 --- a/AsyncDisplayKit/Details/ASCollectionViewLayoutController.mm +++ b/AsyncDisplayKit/Details/ASCollectionViewLayoutController.mm @@ -78,20 +78,6 @@ typedef struct ASRangeGeometry ASRangeGeometry; return self; } -- (instancetype)initWithScrollView:(UIScrollView *)scrollView collectionViewLayout:(UICollectionViewLayout *)layout -{ - if (!(self = [super init])) { - return nil; - } - - _scrollableDirections = ASScrollDirectionVerticalDirections; - _scrollView = scrollView; - _collectionViewLayout = layout; - _updateRangeBoundsIndexedByRangeType = std::vector(ASLayoutRangeTypeCount); - return self; -} - - #pragma mark - #pragma mark Index Paths in Range diff --git a/AsyncDisplayKit/Details/ASDataController.h b/AsyncDisplayKit/Details/ASDataController.h index 3254655fcb..08dfd4fbf2 100644 --- a/AsyncDisplayKit/Details/ASDataController.h +++ b/AsyncDisplayKit/Details/ASDataController.h @@ -8,7 +8,7 @@ #import #import - +#import "ASFlowLayoutController.h" @class ASCellNode; @class ASDataController; @@ -97,7 +97,8 @@ typedef NSUInteger ASDataControllerAnimationOptions; * will be updated asynchronously. The dataSource must be updated to reflect the changes before these methods has been called. * For each data updatin, the corresponding methods in delegate will be called. */ -@interface ASDataController : ASDealloc2MainObject +@protocol ASFlowLayoutControllerDataSource; +@interface ASDataController : ASDealloc2MainObject /** Data source for fetching data info. @@ -167,4 +168,6 @@ typedef NSUInteger ASDataControllerAnimationOptions; - (NSArray *)nodesAtIndexPaths:(NSArray *)indexPaths; +- (NSArray *)completedNodes; // This provides efficient access to the entire _completedNodes multidimensional array. + @end diff --git a/AsyncDisplayKit/Details/ASDataController.mm b/AsyncDisplayKit/Details/ASDataController.mm index 25b6518e21..c3d1a916c6 100644 --- a/AsyncDisplayKit/Details/ASDataController.mm +++ b/AsyncDisplayKit/Details/ASDataController.mm @@ -54,7 +54,6 @@ static void *kASSizingQueueContext = &kASSizingQueueContext; _pendingEditCommandBlocks = [NSMutableArray array]; _editingTransactionQueue = [[NSOperationQueue alloc] init]; - _editingTransactionQueue.qualityOfService = NSQualityOfServiceUserInitiated; _editingTransactionQueue.maxConcurrentOperationCount = 1; // Serial queue _editingTransactionQueue.name = @"org.AsyncDisplayKit.ASDataController.editingTransactionQueue"; @@ -553,17 +552,15 @@ static void *kASSizingQueueContext = &kASSizingQueueContext; - (NSArray *)nodesAtIndexPaths:(NSArray *)indexPaths { ASDisplayNodeAssertMainThread(); - - // Make sure that any asynchronous layout operations have finished so that those nodes are present. - // Otherwise a failure case could be: - // - Reload section 2, deleting all current nodes in that section. - // - New nodes are created and sizing is triggered, but they are not yet added to _completedNodes. - // - This method is called and includes an indexPath in section 2. - // - Unless we wait for the layout group to finish, we will crash with array out of bounds looking for the index in _completedNodes. - return ASFindElementsInMultidimensionalArrayAtIndexPaths(_completedNodes, [indexPaths sortedArrayUsingSelector:@selector(compare:)]); } +- (NSArray *)completedNodes +{ + ASDisplayNodeAssertMainThread(); + return _completedNodes; +} + #pragma mark - Dealloc - (void)dealloc diff --git a/AsyncDisplayKit/Details/ASFlowLayoutController.h b/AsyncDisplayKit/Details/ASFlowLayoutController.h index 0c682594cb..01da06d124 100644 --- a/AsyncDisplayKit/Details/ASFlowLayoutController.h +++ b/AsyncDisplayKit/Details/ASFlowLayoutController.h @@ -15,12 +15,20 @@ typedef NS_ENUM(NSUInteger, ASFlowLayoutDirection) { ASFlowLayoutDirectionHorizontal, }; +@protocol ASFlowLayoutControllerDataSource + +- (NSArray *)completedNodes; // This provides access to ASDataController's _completedNodes multidimensional array. + +@end + /** - * The controller for flow layout. + * An optimized flow layout controller that supports only vertical or horizontal scrolling, not simultaneously two-dimensional scrolling. + * It is used for all ASTableViews, and may be used with ASCollectionView. */ @interface ASFlowLayoutController : ASAbstractLayoutController @property (nonatomic, readonly, assign) ASFlowLayoutDirection layoutDirection; +@property (nonatomic) id dataSource; - (instancetype)initWithScrollOption:(ASFlowLayoutDirection)layoutDirection; diff --git a/AsyncDisplayKit/Details/ASFlowLayoutController.mm b/AsyncDisplayKit/Details/ASFlowLayoutController.mm index 5bac784679..52b9e6e880 100644 --- a/AsyncDisplayKit/Details/ASFlowLayoutController.mm +++ b/AsyncDisplayKit/Details/ASFlowLayoutController.mm @@ -7,110 +7,66 @@ */ #import "ASFlowLayoutController.h" +#import "ASAssert.h" +#import "ASDisplayNode.h" +#import "ASIndexPath.h" #include #include #include -#import "ASAssert.h" - static const CGFloat kASFlowLayoutControllerRefreshingThreshold = 0.3; -@interface ASFlowLayoutController() { - std::vector > _nodeSizes; - - std::pair _visibleRangeStartPos; - std::pair _visibleRangeEndPos; - - std::vector> _rangeStartPos; - std::vector> _rangeEndPos; +@interface ASFlowLayoutController() +{ + ASIndexPathRange _visibleRange; + std::vector _rangesByType; // All ASLayoutRangeTypes besides visible. } @end @implementation ASFlowLayoutController -- (instancetype)initWithScrollOption:(ASFlowLayoutDirection)layoutDirection { +- (instancetype)initWithScrollOption:(ASFlowLayoutDirection)layoutDirection +{ if (!(self = [super init])) { return nil; } - _layoutDirection = layoutDirection; - + _rangesByType = std::vector(ASLayoutRangeTypeCount); return self; } -#pragma mark - Editing - -- (void)insertNodesAtIndexPaths:(NSArray *)indexPaths withSizes:(NSArray *)nodeSizes -{ - ASDisplayNodeAssert(indexPaths.count == nodeSizes.count, @"Inconsistent index paths and node size"); - - [indexPaths enumerateObjectsUsingBlock:^(NSIndexPath *indexPath, NSUInteger idx, BOOL *stop) { - std::vector &v = _nodeSizes[indexPath.section]; - v.insert(v.begin() + indexPath.row, [(NSValue *)nodeSizes[idx] CGSizeValue]); - }]; -} - -- (void)deleteNodesAtIndexPaths:(NSArray *)indexPaths -{ - [indexPaths enumerateObjectsWithOptions:NSEnumerationReverse usingBlock:^(NSIndexPath *indexPath, NSUInteger idx, BOOL *stop) { - std::vector &v = _nodeSizes[indexPath.section]; - v.erase(v.begin() + indexPath.row); - }]; -} - -- (void)insertSections:(NSArray *)sections atIndexSet:(NSIndexSet *)indexSet -{ - __block int cnt = 0; - [indexSet enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL *stop) { - NSArray *nodes = sections[cnt++]; - std::vector v; - v.reserve(nodes.count); - - for (int i = 0; i < nodes.count; i++) { - v.push_back([nodes[i] CGSizeValue]); - } - - _nodeSizes.insert(_nodeSizes.begin() + idx, v); - }]; -} - -- (void)deleteSectionsAtIndexSet:(NSIndexSet *)indexSet { - [indexSet enumerateIndexesWithOptions:NSEnumerationReverse usingBlock:^(NSUInteger idx, BOOL *stop) { - _nodeSizes.erase(_nodeSizes.begin() +idx); - }]; -} - #pragma mark - Visible Indices - (BOOL)shouldUpdateForVisibleIndexPaths:(NSArray *)indexPaths viewportSize:(CGSize)viewportSize rangeType:(ASLayoutRangeType)rangeType { - if (!indexPaths.count) { + if (!indexPaths.count || rangeType >= _rangesByType.size()) { return NO; } - std::pair rangeStartPos, rangeEndPos; - - if (rangeType < _rangeStartPos.size() && rangeType < _rangeEndPos.size()) { - rangeStartPos = _rangeStartPos[rangeType]; - rangeEndPos = _rangeEndPos[rangeType]; - } - - std::pair startPos, endPos; - ASFindIndexPathRange(indexPaths, startPos, endPos); - - if (rangeStartPos >= startPos || rangeEndPos <= endPos) { + ASIndexPathRange existingRange = _rangesByType[rangeType]; + ASIndexPathRange newRange = [self indexPathRangeForIndexPaths:indexPaths]; + + ASIndexPath maximumStart = ASIndexPathMaximum(existingRange.start, newRange.start); + ASIndexPath minimumEnd = ASIndexPathMinimum(existingRange.end, newRange.end); + + if (ASIndexPathEqualToIndexPath(maximumStart, existingRange.start) || ASIndexPathEqualToIndexPath(minimumEnd, existingRange.end)) { return YES; } - return ASFlowLayoutDistance(startPos, _visibleRangeStartPos, _nodeSizes) > ASFlowLayoutDistance(_visibleRangeStartPos, rangeStartPos, _nodeSizes) * kASFlowLayoutControllerRefreshingThreshold || - ASFlowLayoutDistance(endPos, _visibleRangeEndPos, _nodeSizes) > ASFlowLayoutDistance(_visibleRangeEndPos, rangeEndPos, _nodeSizes) * kASFlowLayoutControllerRefreshingThreshold; + NSInteger newStartDelta = [self flowLayoutDistanceForRange:ASIndexPathRangeMake(_visibleRange.start, newRange.start)]; + NSInteger existingStartDelta = [self flowLayoutDistanceForRange:ASIndexPathRangeMake(_visibleRange.start, existingRange.start)] * kASFlowLayoutControllerRefreshingThreshold; + + NSInteger newEndDelta = [self flowLayoutDistanceForRange:ASIndexPathRangeMake(_visibleRange.end, newRange.end)]; + NSInteger existingEndDelta = [self flowLayoutDistanceForRange:ASIndexPathRangeMake(_visibleRange.end, existingRange.end)] * kASFlowLayoutControllerRefreshingThreshold; + + return (newStartDelta > existingStartDelta) || (newEndDelta > existingEndDelta); } - (void)setVisibleNodeIndexPaths:(NSArray *)indexPaths { - ASFindIndexPathRange(indexPaths, _visibleRangeStartPos, _visibleRangeEndPos); + _visibleRange = [self indexPathRangeForIndexPaths:indexPaths]; } /** @@ -138,100 +94,134 @@ static const CGFloat kASFlowLayoutControllerRefreshingThreshold = 0.3; CGFloat backScreens = scrollDirection == leadingDirection ? tuningParameters.leadingBufferScreenfuls : tuningParameters.trailingBufferScreenfuls; CGFloat frontScreens = scrollDirection == leadingDirection ? tuningParameters.trailingBufferScreenfuls : tuningParameters.leadingBufferScreenfuls; - std::pair startIter = ASFindIndexForRange(_nodeSizes, _visibleRangeStartPos, - backScreens * viewportScreenMetric, _layoutDirection); - std::pair endIter = ASFindIndexForRange(_nodeSizes, _visibleRangeEndPos, frontScreens * viewportScreenMetric, _layoutDirection); + + ASIndexPath startPath = [self findIndexPathAtDistance:(-backScreens * viewportScreenMetric) fromIndexPath:_visibleRange.start]; + ASIndexPath endPath = [self findIndexPathAtDistance:(frontScreens * viewportScreenMetric) fromIndexPath:_visibleRange.end]; + ASDisplayNodeAssert(startPath.section <= endPath.section, @"startPath should never begin at a further position than endPath"); + NSMutableSet *indexPathSet = [[NSMutableSet alloc] init]; - while (startIter != endIter) { - [indexPathSet addObject:[NSIndexPath indexPathForRow:startIter.second inSection:startIter.first]]; - startIter.second++; + NSArray *completedNodes = [_dataSource completedNodes]; + + while (!ASIndexPathEqualToIndexPath(startPath, endPath)) { + [indexPathSet addObject:[NSIndexPath indexPathWithASIndexPath:startPath]]; + startPath.row++; // Once we reach the end of the section, advance to the next one. Keep advancing if the next section is zero-sized. - while (startIter.second == _nodeSizes[startIter.first].size() && startIter.first < _nodeSizes.size()) { - startIter.second = 0; - startIter.first++; + while (startPath.row >= [(NSArray *)completedNodes[startPath.section] count] && startPath.section < completedNodes.count - 1) { + startPath.row = 0; + startPath.section++; + ASDisplayNodeAssert(startPath.section <= endPath.section, @"startPath should never reach a further section than endPath"); } } - [indexPathSet addObject:[NSIndexPath indexPathForRow:endIter.second inSection:endIter.first]]; + [indexPathSet addObject:[NSIndexPath indexPathWithASIndexPath:endPath]]; return indexPathSet; } #pragma mark - Utility -static void ASFindIndexPathRange(NSArray *indexPaths, std::pair &startPos, std::pair &endPos) - +- (ASIndexPathRange)indexPathRangeForIndexPaths:(NSArray *)indexPaths { - NSIndexPath *initialIndexPath = [indexPaths firstObject]; - startPos = endPos = {initialIndexPath.section, initialIndexPath.row}; + // Set up an initial value so the MIN and MAX can work in the enumeration. + __block ASIndexPath currentIndexPath = [[indexPaths firstObject] ASIndexPathValue]; + __block ASIndexPathRange range; + range.start = currentIndexPath; + range.end = currentIndexPath; + [indexPaths enumerateObjectsUsingBlock:^(NSIndexPath *indexPath, NSUInteger idx, BOOL *stop) { - std::pair p(indexPath.section, indexPath.row); - startPos = MIN(startPos, p); - endPos = MAX(endPos, p); + currentIndexPath = [indexPath ASIndexPathValue]; + range.start = ASIndexPathMinimum(range.start, currentIndexPath); + range.end = ASIndexPathMaximum(range.end, currentIndexPath); }]; + return range; } -static const std::pair ASFindIndexForRange(const std::vector> &nodes, - const std::pair &pos, - CGFloat range, - ASFlowLayoutDirection layoutDirection) +- (ASIndexPath)findIndexPathAtDistance:(CGFloat)distance fromIndexPath:(ASIndexPath)start { - std::pair cur = pos, pre = pos; + // "end" is the index path we'll advance until we have gone far enough from "start" to reach "distance" + ASIndexPath end = start; + // "previous" will store one iteration before "end", in case we go too far and need to reset "end" to be "previous" + ASIndexPath previous = start; - if (range < 0.0 && cur.first >= 0 && cur.first < nodes.size() && cur.second >= 0 && cur.second < nodes[cur.first].size()) { - // search backward - while (range < 0.0 && cur.first >= 0 && cur.second >= 0) { - pre = cur; - CGSize size = nodes[cur.first][cur.second]; - range += layoutDirection == ASFlowLayoutDirectionHorizontal ? size.width : size.height; - cur.second--; - while (cur.second < 0 && cur.first > 0) { - cur.second = (int)nodes[--cur.first].size() - 1; + NSArray *completedNodes = [_dataSource completedNodes]; + NSUInteger numberOfSections = [completedNodes count]; + NSUInteger numberOfRowsInSection = [(NSArray *)completedNodes[end.section] count]; + + // If "distance" is negative, advance "end" backwards across rows and sections. + // Otherwise, advance forward. In either case, bring "distance" closer to zero by the dimension of each row passed. + if (distance < 0.0 && end.section >= 0 && end.section < numberOfSections && end.row >= 0 && end.row < numberOfRowsInSection) { + while (distance < 0.0 && end.section >= 0 && end.row >= 0) { + previous = end; + ASDisplayNode *node = completedNodes[end.section][end.row]; + CGSize size = node.calculatedSize; + distance += (_layoutDirection == ASFlowLayoutDirectionHorizontal ? size.width : size.height); + end.row--; + // If we've gone to a negative row, set to the last row of the previous section. While loop is required to handle empty sections. + while (end.row < 0 && end.section > 0) { + end.section--; + numberOfRowsInSection = [(NSArray *)completedNodes[end.section] count]; + end.row = numberOfRowsInSection - 1; } } - if (cur.second < 0) { - cur = pre; + if (end.row < 0) { + end = previous; } } else { - // search forward - while (range > 0.0 && cur.first >= 0 && cur.first < nodes.size() && cur.second >= 0 && cur.second < nodes[cur.first].size()) { - pre = cur; - CGSize size = nodes[cur.first][cur.second]; - range -= layoutDirection == ASFlowLayoutDirectionHorizontal ? size.width : size.height; + while (distance > 0.0 && end.section >= 0 && end.section < numberOfSections && end.row >= 0 && end.row < numberOfRowsInSection) { + previous = end; + ASDisplayNode *node = completedNodes[end.section][end.row]; + CGSize size = node.calculatedSize; + distance -= _layoutDirection == ASFlowLayoutDirectionHorizontal ? size.width : size.height; - cur.second++; - while (cur.second == nodes[cur.first].size() && cur.first < (int)nodes.size() - 1) { - cur.second = 0; - cur.first++; + end.row++; + // If we've gone beyond the section, reset to the beginning of the next section. While loop is required to handle empty sections. + while (end.row >= numberOfRowsInSection && end.section < numberOfSections - 1) { + end.row = 0; + end.section++; + numberOfRowsInSection = [(NSArray *)completedNodes[end.section] count]; } } - if (cur.second == nodes[cur.first].size()) { - cur = pre; + if (end.row >= numberOfRowsInSection) { + end = previous; } } - return cur; + return end; } -static int ASFlowLayoutDistance(const std::pair &start, const std::pair &end, const std::vector> &nodes) +- (NSInteger)flowLayoutDistanceForRange:(ASIndexPathRange)range { - if (start == end) { + // This method should only be called with the range in proper order (start comes before end). + ASDisplayNodeAssert(ASIndexPathEqualToIndexPath(ASIndexPathMinimum(range.start, range.end), range.start), @"flowLayoutDistanceForRange: called with invalid range"); + + if (ASIndexPathEqualToIndexPath(range.start, range.end)) { return 0; - } else if (start > end) { - return - ASFlowLayoutDistance(end, start, nodes); } + + NSInteger totalRowCount = 0; + NSUInteger numberOfRowsInSection = 0; + NSArray *completedNodes = [_dataSource completedNodes]; - int res = 0; - - for (int i = start.first; i <= end.first; i++) { - res += (i == end.first ? end.second + 1 : nodes[i].size()) - (i == start.first ? start.second : 0); + for (NSInteger section = range.start.section; section <= range.end.section; section++) { + numberOfRowsInSection = [(NSArray *)completedNodes[section] count]; + totalRowCount += numberOfRowsInSection; + + if (section == range.start.section) { + // For the start section, make sure we don't count the rows before the start row. + totalRowCount -= range.start.row; + } else if (section == range.end.section) { + // For the start section, make sure we don't count the rows after the end row. + totalRowCount -= (numberOfRowsInSection - (range.end.row + 1)); + } } - - return res; + + ASDisplayNodeAssert(totalRowCount >= 0, @"totalRowCount in flowLayoutDistanceForRange: should not be negative"); + return totalRowCount; } @end diff --git a/AsyncDisplayKit/Details/ASIndexPath.h b/AsyncDisplayKit/Details/ASIndexPath.h new file mode 100644 index 0000000000..9eed7dd247 --- /dev/null +++ b/AsyncDisplayKit/Details/ASIndexPath.h @@ -0,0 +1,84 @@ +// +// ASIndexPath.h +// Pods +// +// Created by Scott Goodson on 7/4/15. +// +// A much more efficient way to handle index paths than NSIndexPath. +// For best results, use C++ vectors; NSValue wrapping with Cocoa collections +// would make NSIndexPath a much better choice. +// + +typedef struct { + NSInteger section; + NSInteger row; +} ASIndexPath; + +typedef struct { + ASIndexPath start; + ASIndexPath end; +} ASIndexPathRange; + +ASIndexPath ASIndexPathMake(NSInteger section, NSInteger row) +{ + ASIndexPath indexPath; + indexPath.section = section; + indexPath.row = row; + return indexPath; +} + +BOOL ASIndexPathEqualToIndexPath(ASIndexPath first, ASIndexPath second) +{ + return (first.section == second.section && first.row == second.row); +} + +ASIndexPath ASIndexPathMinimum(ASIndexPath first, ASIndexPath second) +{ + if (first.section < second.section) { + return first; + } else if (first.section > second.section) { + return second; + } else { + return (first.row < second.row ? first : second); + } +} + +ASIndexPath ASIndexPathMaximum(ASIndexPath first, ASIndexPath second) +{ + if (first.section > second.section) { + return first; + } else if (first.section < second.section) { + return second; + } else { + return (first.row > second.row ? first : second); + } +} + +ASIndexPathRange ASIndexPathRangeMake(ASIndexPath first, ASIndexPath second) +{ + ASIndexPathRange range; + range.start = ASIndexPathMinimum(first, second); + range.end = ASIndexPathMaximum(first, second); + return range; +} + +BOOL ASIndexPathRangeEqualToIndexPathRange(ASIndexPathRange first, ASIndexPathRange second) +{ + return ASIndexPathEqualToIndexPath(first.start, second.start) && ASIndexPathEqualToIndexPath(first.end, second.end); +} + +@interface NSIndexPath (ASIndexPathAdditions) ++ (NSIndexPath *)indexPathWithASIndexPath:(ASIndexPath)indexPath; +- (ASIndexPath)ASIndexPathValue; +@end + +@implementation NSIndexPath (ASIndexPathAdditions) ++ (NSIndexPath *)indexPathWithASIndexPath:(ASIndexPath)indexPath +{ + return [NSIndexPath indexPathForRow:indexPath.row inSection:indexPath.section];; +} +- (ASIndexPath)ASIndexPathValue +{ + return ASIndexPathMake(self.section, self.row); +} +@end diff --git a/AsyncDisplayKit/Details/ASRangeController.mm b/AsyncDisplayKit/Details/ASRangeController.mm index 1a6afed732..f41d9d291c 100644 --- a/AsyncDisplayKit/Details/ASRangeController.mm +++ b/AsyncDisplayKit/Details/ASRangeController.mm @@ -191,9 +191,6 @@ }]; ASDisplayNodePerformBlockOnMainThread(^{ - if ([_layoutController respondsToSelector:@selector(insertNodesAtIndexPaths:withSizes:)]) { - [_layoutController insertNodesAtIndexPaths:indexPaths withSizes:nodeSizes]; - } _rangeIsValid = NO; [_delegate rangeController:self didInsertNodesAtIndexPaths:indexPaths withAnimationOptions:animationOptions]; }); @@ -201,9 +198,6 @@ - (void)dataController:(ASDataController *)dataController didDeleteNodesAtIndexPaths:(NSArray *)indexPaths withAnimationOptions:(ASDataControllerAnimationOptions)animationOptions { ASDisplayNodePerformBlockOnMainThread(^{ - if ([_layoutController respondsToSelector:@selector(deleteNodesAtIndexPaths:)]) { - [_layoutController deleteNodesAtIndexPaths:indexPaths]; - } _rangeIsValid = NO; [_delegate rangeController:self didDeleteNodesAtIndexPaths:indexPaths withAnimationOptions:animationOptions]; }); @@ -223,9 +217,6 @@ }]; ASDisplayNodePerformBlockOnMainThread(^{ - if ([_layoutController respondsToSelector:@selector(insertSections:atIndexSet:)]) { - [_layoutController insertSections:sectionNodeSizes atIndexSet:indexSet]; - } _rangeIsValid = NO; [_delegate rangeController:self didInsertSectionsAtIndexSet:indexSet withAnimationOptions:animationOptions]; }); @@ -233,9 +224,6 @@ - (void)dataController:(ASDataController *)dataController didDeleteSectionsAtIndexSet:(NSIndexSet *)indexSet withAnimationOptions:(ASDataControllerAnimationOptions)animationOptions { ASDisplayNodePerformBlockOnMainThread(^{ - if ([_layoutController respondsToSelector:@selector(deleteSectionsAtIndexSet:)]) { - [_layoutController deleteSectionsAtIndexSet:indexSet]; - } _rangeIsValid = NO; [_delegate rangeController:self didDeleteSectionsAtIndexSet:indexSet withAnimationOptions:animationOptions]; });