diff --git a/AsyncDisplayKit/ASCollectionView.mm b/AsyncDisplayKit/ASCollectionView.mm index 0835dcfbe1..950cba8f76 100644 --- a/AsyncDisplayKit/ASCollectionView.mm +++ b/AsyncDisplayKit/ASCollectionView.mm @@ -106,9 +106,6 @@ static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell"; NSMutableArray *_batchUpdateBlocks; BOOL _asyncDataFetchingEnabled; - BOOL _asyncDelegateImplementsScrollviewDidScroll; - BOOL _asyncDataSourceImplementsConstrainedSizeForNode; - BOOL _asyncDataSourceImplementsNodeBlockForItemAtIndexPath; _ASCollectionViewNodeSizeInvalidationContext *_queuedNodeSizeInvalidationContext; // Main thread only 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. */ 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; @@ -333,16 +350,22 @@ static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell"; if (asyncDataSource == nil) { _asyncDataSource = nil; _proxyDataSource = _isDeallocating ? nil : [[ASCollectionViewProxy alloc] initWithTarget:nil interceptor:self]; - _asyncDataSourceImplementsConstrainedSizeForNode = NO; - _asyncDataSourceImplementsNodeBlockForItemAtIndexPath = NO; + + memset(&_asyncDataSourceFlags, 0, sizeof(_asyncDataSourceFlags)); } else { _asyncDataSource = asyncDataSource; _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: - ASDisplayNodeAssertTrue(_asyncDataSourceImplementsNodeBlockForItemAtIndexPath || [_asyncDataSource respondsToSelector:@selector(collectionView:nodeForItemAtIndexPath:)]); + ASDisplayNodeAssertTrue(_asyncDataSourceFlags.asyncDataSourceNodeBlockForItemAtIndexPath || _asyncDataSourceFlags.asyncDataSourceNodeForItemAtIndexPath); } super.dataSource = (id)_proxyDataSource; @@ -363,11 +386,19 @@ static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell"; if (asyncDelegate == nil) { _asyncDelegate = nil; _proxyDelegate = _isDeallocating ? nil : [[ASCollectionViewProxy alloc] initWithTarget:nil interceptor:self]; - _asyncDelegateImplementsScrollviewDidScroll = NO; + + memset(&_asyncDelegateFlags, 0, sizeof(_asyncDelegateFlags)); } else { _asyncDelegate = asyncDelegate; _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)_proxyDelegate; @@ -566,7 +597,7 @@ static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell"; ASCellNode *cellNode = [cell node]; cellNode.scrollView = collectionView; - if ([_asyncDelegate respondsToSelector:@selector(collectionView:willDisplayNodeForItemAtIndexPath:)]) { + if (_asyncDelegateFlags.asyncDelegateCollectionViewWillDisplayNodeForItemAtIndexPath) { [_asyncDelegate collectionView:self willDisplayNodeForItemAtIndexPath:indexPath]; } @@ -586,7 +617,7 @@ static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell"; 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."); [_asyncDelegate collectionView:self didEndDisplayingNode:cellNode forItemAtIndexPath:indexPath]; } @@ -597,7 +628,7 @@ static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell"; #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wdeprecated-declarations" - if ([_asyncDelegate respondsToSelector:@selector(collectionView:didEndDisplayingNodeForItemAtIndexPath:)]) { + if (_asyncDelegateFlags.asyncDelegateCollectionViewDidEndDisplayingNodeForItemAtIndexPathDeprecated) { [_asyncDelegate collectionView:self didEndDisplayingNodeForItemAtIndexPath:indexPath]; } #pragma clang diagnostic pop @@ -620,7 +651,7 @@ static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell"; inScrollView:scrollView withCellFrame:collectionCell.frame]; } - if (_asyncDelegateImplementsScrollviewDidScroll) { + if (_asyncDelegateFlags.asyncDelegateScrollViewDidScroll) { [_asyncDelegate scrollViewDidScroll:scrollView]; } } @@ -637,7 +668,7 @@ static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell"; [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]; } } @@ -747,8 +778,8 @@ static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell"; - (BOOL)canBatchFetch { // if the delegate does not respond to this method, there is no point in starting to fetch - BOOL canFetch = [_asyncDelegate respondsToSelector:@selector(collectionView:willBeginBatchFetchWithContext:)]; - if (canFetch && [_asyncDelegate respondsToSelector:@selector(shouldBatchFetchForCollectionView:)]) { + BOOL canFetch = _asyncDelegateFlags.asyncDelegateCollectionViewWillBeginBatchFetchWithContext; + if (canFetch && _asyncDelegateFlags.asyncDelegateShouldBatchFetchForCollectionView) { return [_asyncDelegate shouldBatchFetchForCollectionView:self]; } else { return canFetch; @@ -788,7 +819,7 @@ static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell"; - (void)_beginBatchFetching { [_batchContext beginBatchFetching]; - if ([_asyncDelegate respondsToSelector:@selector(collectionView:willBeginBatchFetchWithContext:)]) { + if (_asyncDelegateFlags.asyncDelegateCollectionViewWillBeginBatchFetchWithContext) { dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ [_asyncDelegate collectionView:self willBeginBatchFetchWithContext:_batchContext]; }); @@ -800,7 +831,7 @@ static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell"; - (ASCellNodeBlock)dataController:(ASDataController *)dataController nodeBlockAtIndexPath:(NSIndexPath *)indexPath { - if (!_asyncDataSourceImplementsNodeBlockForItemAtIndexPath) { + if (!_asyncDataSourceFlags.asyncDataSourceNodeBlockForItemAtIndexPath) { ASCellNode *node = [_asyncDataSource collectionView:self nodeForItemAtIndexPath:indexPath]; ASDisplayNodeAssert([node isKindOfClass:ASCellNode.class], @"invalid node class, expected ASCellNode"); __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 // implement a custom inspector. - if (_asyncDataSourceImplementsConstrainedSizeForNode) { + if (_asyncDataSourceFlags.asyncDataSourceConstrainedSizeForNode) { constrainedSize = [_asyncDataSource collectionView:self constrainedSizeForNodeAtIndexPath:indexPath]; } else { CGSize maxSize = CGSizeEqualToSize(_maxSizeForNodesConstrainedSize, CGSizeZero) ? self.bounds.size : _maxSizeForNodesConstrainedSize; @@ -863,7 +894,7 @@ static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell"; } - (NSUInteger)numberOfSectionsInDataController:(ASDataController *)dataController { - if ([_asyncDataSource respondsToSelector:@selector(numberOfSectionsInCollectionView:)]) { + if (_asyncDataSourceFlags.asyncDataSourceNumberOfSectionsInCollectionView) { return [_asyncDataSource numberOfSectionsInCollectionView:self]; } else { return 1; @@ -875,7 +906,7 @@ static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell"; ASDisplayNodeAssert(!self.asyncDataSourceLocked, @"The data source has already been locked"); self.asyncDataSourceLocked = YES; - if ([_asyncDataSource respondsToSelector:@selector(collectionViewLockDataSource:)]) { + if (_asyncDataSourceFlags.asyncDataSourceCollectionViewLockDataSource) { [_asyncDataSource collectionViewLockDataSource:self]; } } @@ -885,7 +916,7 @@ static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell"; ASDisplayNodeAssert(self.asyncDataSourceLocked, @"The data source has already been unlocked"); self.asyncDataSourceLocked = NO; - if ([_asyncDataSource respondsToSelector:@selector(collectionViewUnlockDataSource:)]) { + if (_asyncDataSourceFlags.asyncDataSourceCollectionViewUnlockDataSource) { [_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 } + [_layoutFacilitator collectionViewWillEditCellsAtIndexPaths:indexPaths batched:_performingBatchUpdates]; if (_performingBatchUpdates) { - [_layoutFacilitator collectionViewWillEditCellsAtIndexPaths:indexPaths batched:YES]; [_batchUpdateBlocks addObject:^{ [super insertItemsAtIndexPaths:indexPaths]; }]; } else { - [_layoutFacilitator collectionViewWillEditCellsAtIndexPaths:indexPaths batched:NO]; [UIView performWithoutAnimation:^{ [super insertItemsAtIndexPaths:indexPaths]; [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 } + [_layoutFacilitator collectionViewWillEditCellsAtIndexPaths:indexPaths batched:_performingBatchUpdates]; if (_performingBatchUpdates) { - [_layoutFacilitator collectionViewWillEditCellsAtIndexPaths:indexPaths batched:YES]; [_batchUpdateBlocks addObject:^{ [super deleteItemsAtIndexPaths:indexPaths]; }]; } else { - [_layoutFacilitator collectionViewWillEditCellsAtIndexPaths:indexPaths batched:NO]; [UIView performWithoutAnimation:^{ [super deleteItemsAtIndexPaths:indexPaths]; [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 } + [_layoutFacilitator collectionViewWillEditSectionsAtIndexSet:indexSet batched:_performingBatchUpdates]; if (_performingBatchUpdates) { - [_layoutFacilitator collectionViewWillEditSectionsAtIndexSet:indexSet batched:YES]; [_batchUpdateBlocks addObject:^{ [super insertSections:indexSet]; }]; } else { - [_layoutFacilitator collectionViewWillEditSectionsAtIndexSet:indexSet batched:NO]; [UIView performWithoutAnimation:^{ [super insertSections:indexSet]; [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 } + [_layoutFacilitator collectionViewWillEditSectionsAtIndexSet:indexSet batched:_performingBatchUpdates]; if (_performingBatchUpdates) { - [_layoutFacilitator collectionViewWillEditSectionsAtIndexSet:indexSet batched:YES]; [_batchUpdateBlocks addObject:^{ [super deleteSections:indexSet]; }]; } else { - [_layoutFacilitator collectionViewWillEditSectionsAtIndexSet:indexSet batched:NO]; [UIView performWithoutAnimation:^{ [super deleteSections:indexSet]; [self _scheduleCheckForBatchFetchingForNumberOfChanges:indexSet.count]; diff --git a/AsyncDisplayKit/ASTableView.mm b/AsyncDisplayKit/ASTableView.mm index 6718932297..5fe3d06694 100644 --- a/AsyncDisplayKit/ASTableView.mm +++ b/AsyncDisplayKit/ASTableView.mm @@ -112,9 +112,25 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell"; BOOL _ignoreNodesConstrainedWidthChange; BOOL _queuedNodeHeightUpdate; BOOL _isDeallocating; - BOOL _dataSourceImplementsNodeBlockForRowAtIndexPath; - BOOL _asyncDelegateImplementsScrollviewDidScroll; 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; @@ -260,13 +276,20 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell"; if (asyncDataSource == nil) { _asyncDataSource = nil; _proxyDataSource = _isDeallocating ? nil : [[ASTableViewProxy alloc] initWithTarget:nil interceptor:self]; - _dataSourceImplementsNodeBlockForRowAtIndexPath = NO; + + memset(&_asyncDataSourceFlags, 0, sizeof(_asyncDataSourceFlags)); } else { _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]; + + _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)_proxyDataSource; @@ -287,11 +310,19 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell"; if (asyncDelegate == nil) { _asyncDelegate = nil; _proxyDelegate = _isDeallocating ? nil : [[ASTableViewProxy alloc] initWithTarget:nil interceptor:self]; - _asyncDelegateImplementsScrollviewDidScroll = NO; + + memset(&_asyncDelegateFlags, 0, sizeof(_asyncDelegateFlags)); } else { _asyncDelegate = asyncDelegate; - _asyncDelegateImplementsScrollviewDidScroll = [_asyncDelegate respondsToSelector:@selector(scrollViewDidScroll:)]; _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)_proxyDelegate; @@ -584,7 +615,7 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell"; ASCellNode *cellNode = [cell node]; cellNode.scrollView = tableView; - if ([_asyncDelegate respondsToSelector:@selector(tableView:willDisplayNodeForRowAtIndexPath:)]) { + if (_asyncDelegateFlags.asyncDelegateTableViewWillDisplayNodeForRowAtIndexPath) { [_asyncDelegate tableView:self willDisplayNodeForRowAtIndexPath:indexPath]; } @@ -609,7 +640,7 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell"; [_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."); [_asyncDelegate tableView:self didEndDisplayingNode:cellNode forRowAtIndexPath:indexPath]; } @@ -620,7 +651,7 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell"; #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wdeprecated-declarations" - if ([_asyncDelegate respondsToSelector:@selector(tableView:didEndDisplayingNodeForRowAtIndexPath:)]) { + if (_asyncDelegateFlags.asyncDelegateTableViewDidEndDisplayingNodeForRowAtIndexPathDeprecated) { [_asyncDelegate tableView:self didEndDisplayingNodeForRowAtIndexPath:indexPath]; } #pragma clang diagnostic pop @@ -642,7 +673,7 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell"; inScrollView:scrollView withCellFrame:tableCell.frame]; } - if (_asyncDelegateImplementsScrollviewDidScroll) { + if (_asyncDelegateFlags.asyncDelegateScrollViewDidScroll) { [_asyncDelegate scrollViewDidScroll:scrollView]; } } @@ -659,7 +690,7 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell"; [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]; } } @@ -722,8 +753,8 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell"; - (BOOL)canBatchFetch { // if the delegate does not respond to this method, there is no point in starting to fetch - BOOL canFetch = [_asyncDelegate respondsToSelector:@selector(tableView:willBeginBatchFetchWithContext:)]; - if (canFetch && [_asyncDelegate respondsToSelector:@selector(shouldBatchFetchForTableView:)]) { + BOOL canFetch = _asyncDelegateFlags.asyncDelegateTableViewWillBeginBatchFetchWithContext; + if (canFetch && _asyncDelegateFlags.asyncDelegateShouldBatchFetchForTableView) { return [_asyncDelegate shouldBatchFetchForTableView:self]; } else { return canFetch; @@ -763,7 +794,7 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell"; - (void)_beginBatchFetching { [_batchContext beginBatchFetching]; - if ([_asyncDelegate respondsToSelector:@selector(tableView:willBeginBatchFetchWithContext:)]) { + if (_asyncDelegateFlags.asyncDelegateTableViewWillBeginBatchFetchWithContext) { dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ [_asyncDelegate tableView:self willBeginBatchFetchWithContext:_batchContext]; }); @@ -1013,7 +1044,7 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell"; self.asyncDataSourceLocked = YES; - if ([_asyncDataSource respondsToSelector:@selector(tableViewLockDataSource:)]) { + if (_asyncDataSourceFlags.asyncDataSourceTableViewLockDataSource) { [_asyncDataSource tableViewLockDataSource:self]; } } @@ -1024,7 +1055,7 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell"; self.asyncDataSourceLocked = NO; - if ([_asyncDataSource respondsToSelector:@selector(tableViewUnlockDataSource:)]) { + if (_asyncDataSourceFlags.asyncDataSourceTableViewUnlockDataSource) { [_asyncDataSource tableViewUnlockDataSource:self]; } } @@ -1036,7 +1067,7 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell"; - (NSUInteger)numberOfSectionsInDataController:(ASDataController *)dataController { - if ([_asyncDataSource respondsToSelector:@selector(numberOfSectionsInTableView:)]) { + if (_asyncDataSourceFlags.asyncDataSourceNumberOfSectionsInTableView) { return [_asyncDataSource numberOfSectionsInTableView:self]; } else { return 1; // default section number