remove program

This commit is contained in:
Li Tan 2015-02-04 14:42:09 -08:00
parent f8037d435e
commit 25bdd0d84d
6 changed files with 148 additions and 136 deletions

View File

@ -98,6 +98,9 @@ static BOOL _isInterceptedSelector(SEL sel)
ASDataController *_dataController; ASDataController *_dataController;
ASRangeController *_rangeController; ASRangeController *_rangeController;
ASFlowLayoutController *_layoutController; ASFlowLayoutController *_layoutController;
BOOL _batchUpdateFlag;
NSMutableArray *_batchUpdateBlocks;
} }
@end @end
@ -128,6 +131,9 @@ static BOOL _isInterceptedSelector(SEL sel)
_proxyDelegate = [[_ASCollectionViewProxy alloc] initWithTarget:nil interceptor:self]; _proxyDelegate = [[_ASCollectionViewProxy alloc] initWithTarget:nil interceptor:self];
super.delegate = (id<UICollectionViewDelegate>)_proxyDelegate; super.delegate = (id<UICollectionViewDelegate>)_proxyDelegate;
_batchUpdateFlag = NO;
_batchUpdateBlocks = [NSMutableArray array];
[self registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:@"_ASCollectionViewCell"]; [self registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:@"_ASCollectionViewCell"];
return self; return self;
@ -211,6 +217,13 @@ static BOOL _isInterceptedSelector(SEL sel)
#pragma mark Assertions. #pragma mark Assertions.
- (void)performBatchUpdates:(void (^)())updates completion:(void (^)(BOOL))completion
{
[_dataController beginUpdates];
updates();
[_dataController endUpdatesWithCompletion:completion];
}
- (void)insertSections:(NSIndexSet *)sections - (void)insertSections:(NSIndexSet *)sections
{ {
[_dataController insertSections:sections withAnimationOption:kASCollectionViewAnimationNone]; [_dataController insertSections:sections withAnimationOption:kASCollectionViewAnimationNone];
@ -366,9 +379,25 @@ static BOOL _isInterceptedSelector(SEL sel)
#pragma mark ASRangeControllerDelegate. #pragma mark ASRangeControllerDelegate.
- (void)rangeControllerBeginUpdates:(ASRangeController *)rangeController { - (void)rangeControllerBeginUpdates:(ASRangeController *)rangeController {
ASDisplayNodeAssertMainThread();
_batchUpdateFlag = YES;
} }
- (void)rangeControllerEndUpdates:(ASRangeController *)rangeController { - (void)rangeControllerEndUpdates:(ASRangeController *)rangeController completion:(void (^)(BOOL))completion {
ASDisplayNodeAssertMainThread();
[super performBatchUpdates:^{
[_batchUpdateBlocks enumerateObjectsUsingBlock:^(dispatch_block_t block, NSUInteger idx, BOOL *stop) {
block();
}];
} completion:^(BOOL finished) {
if (completion) {
completion(finished);
}
}];
[_batchUpdateBlocks removeAllObjects];
_batchUpdateFlag = NO;
} }
- (NSArray *)rangeControllerVisibleNodeIndexPaths:(ASRangeController *)rangeController - (NSArray *)rangeControllerVisibleNodeIndexPaths:(ASRangeController *)rangeController
@ -391,33 +420,60 @@ static BOOL _isInterceptedSelector(SEL sel)
- (void)rangeController:(ASRangeController *)rangeController didInsertNodesAtIndexPaths:(NSArray *)indexPaths withAnimationOption:(ASDataControllerAnimationOptions)animationOption - (void)rangeController:(ASRangeController *)rangeController didInsertNodesAtIndexPaths:(NSArray *)indexPaths withAnimationOption:(ASDataControllerAnimationOptions)animationOption
{ {
ASDisplayNodeAssertMainThread(); ASDisplayNodeAssertMainThread();
[UIView performWithoutAnimation:^{ if (_batchUpdateFlag) {
[super insertItemsAtIndexPaths:indexPaths]; [_batchUpdateBlocks addObject:^{
}]; [super insertItemsAtIndexPaths:indexPaths];
}];
} else {
[UIView performWithoutAnimation:^{
[super insertItemsAtIndexPaths:indexPaths];
}];
}
} }
- (void)rangeController:(ASRangeController *)rangeController didDeleteNodesAtIndexPaths:(NSArray *)indexPaths withAnimationOption:(ASDataControllerAnimationOptions)animationOption - (void)rangeController:(ASRangeController *)rangeController didDeleteNodesAtIndexPaths:(NSArray *)indexPaths withAnimationOption:(ASDataControllerAnimationOptions)animationOption
{ {
ASDisplayNodeAssertMainThread(); ASDisplayNodeAssertMainThread();
[UIView performWithoutAnimation:^{
[super deleteItemsAtIndexPaths:indexPaths]; if (_batchUpdateFlag) {
}]; [_batchUpdateBlocks addObject:^{
[super deleteItemsAtIndexPaths:indexPaths];
}];
} else {
[UIView performWithoutAnimation:^{
[super deleteItemsAtIndexPaths:indexPaths];
}];
}
} }
- (void)rangeController:(ASRangeController *)rangeController didInsertSectionsAtIndexSet:(NSIndexSet *)indexSet withAnimationOption:(ASDataControllerAnimationOptions)animationOption - (void)rangeController:(ASRangeController *)rangeController didInsertSectionsAtIndexSet:(NSIndexSet *)indexSet withAnimationOption:(ASDataControllerAnimationOptions)animationOption
{ {
ASDisplayNodeAssertMainThread(); ASDisplayNodeAssertMainThread();
[UIView performWithoutAnimation:^{
[super insertSections:indexSet]; if (_batchUpdateFlag) {
}]; [_batchUpdateBlocks addObject:^{
[super insertSections:indexSet];
}];
} else {
[UIView performWithoutAnimation:^{
[super insertSections:indexSet];
}];
}
} }
- (void)rangeController:(ASRangeController *)rangeController didDeleteSectionsAtIndexSet:(NSIndexSet *)indexSet withAnimationOption:(ASDataControllerAnimationOptions)animationOption - (void)rangeController:(ASRangeController *)rangeController didDeleteSectionsAtIndexSet:(NSIndexSet *)indexSet withAnimationOption:(ASDataControllerAnimationOptions)animationOption
{ {
ASDisplayNodeAssertMainThread(); ASDisplayNodeAssertMainThread();
[UIView performWithoutAnimation:^{
[super deleteSections:indexSet]; if (_batchUpdateFlag) {
}]; [_batchUpdateBlocks addObject:^{
[super deleteSections:indexSet];
}];
} else {
[UIView performWithoutAnimation:^{
[super deleteSections:indexSet];
}];
}
} }
@end @end

View File

@ -216,10 +216,6 @@ static BOOL _isInterceptedSelector(SEL sel)
return visibleNodes; return visibleNodes;
} }
#pragma mark -
#pragma mark Assertions
- (void)beginUpdates - (void)beginUpdates
{ {
[_dataController beginUpdates]; [_dataController beginUpdates];
@ -360,10 +356,14 @@ static BOOL _isInterceptedSelector(SEL sel)
[super beginUpdates]; [super beginUpdates];
} }
- (void)rangeControllerEndUpdates:(ASRangeController *)rangeController - (void)rangeControllerEndUpdates:(ASRangeController *)rangeController completion:(void (^)(BOOL))completion
{ {
ASDisplayNodeAssertMainThread(); ASDisplayNodeAssertMainThread();
[super endUpdates]; [super endUpdates];
if (completion) {
completion(YES);
}
} }
- (NSArray *)rangeControllerVisibleNodeIndexPaths:(ASRangeController *)rangeController - (NSArray *)rangeControllerVisibleNodeIndexPaths:(ASRangeController *)rangeController

View File

@ -48,7 +48,7 @@ typedef NSUInteger ASDataControllerAnimationOptions;
Called for batch update. Called for batch update.
*/ */
- (void)dataControllerBeginUpdates:(ASDataController *)dataController; - (void)dataControllerBeginUpdates:(ASDataController *)dataController;
- (void)dataControllerEndUpdates:(ASDataController *)dataController; - (void)dataControllerEndUpdates:(ASDataController *)dataController completion:(void (^)(BOOL))completion;
/** /**
Called for insertion of elements. Called for insertion of elements.
@ -106,6 +106,8 @@ typedef NSUInteger ASDataControllerAnimationOptions;
- (void)endUpdates; - (void)endUpdates;
- (void)endUpdatesWithCompletion:(void (^)(BOOL))completion;
- (void)insertSections:(NSIndexSet *)sections withAnimationOption:(ASDataControllerAnimationOptions)animationOption; - (void)insertSections:(NSIndexSet *)sections withAnimationOption:(ASDataControllerAnimationOptions)animationOption;
- (void)deleteSections:(NSIndexSet *)sections withAnimationOption:(ASDataControllerAnimationOptions)animationOption;; - (void)deleteSections:(NSIndexSet *)sections withAnimationOption:(ASDataControllerAnimationOptions)animationOption;;

View File

@ -54,29 +54,13 @@
} \ } \
} }
//
// The background update is not fully supported yet, although it is trivial to fix it. The underline
// problem is we need to do the profiling between the main thread updating and background updating,
// and then decided which way to go.
//
// For background update, we could avoid the multi-dimensinonal array operation (insertion / deletion)
// on main thread. However, the sideback is we need to dispatch_sync to lock main thread for data query,
// although it is running on a concurrent queue and should be fast enough.
//
// For main thread update, we need to do the multi-dimensional operations (insertion / deletion) on
// main thread, but we will gain the performance in data query. Considering data query is much more
// frequent than data updating, so we keep it on main thread for the initial version.
//
//
#define ENABLE_BACKGROUND_UPDATE 0
const static NSUInteger kASDataControllerSizingCountPerProcessor = 5; const static NSUInteger kASDataControllerSizingCountPerProcessor = 5;
static void *kASSizingQueueContext = &kASSizingQueueContext; static void *kASSizingQueueContext = &kASSizingQueueContext;
static void *kASDataUpdatingQueueContext = &kASDataUpdatingQueueContext;
@interface ASDataController () { @interface ASDataController () {
NSMutableArray *_nodes; NSMutableArray *_nodes;
NSMutableArray *_pendingBlocks;
} }
@property (atomic, assign) NSUInteger batchUpdateCounter; @property (atomic, assign) NSUInteger batchUpdateCounter;
@ -88,6 +72,7 @@ static void *kASDataUpdatingQueueContext = &kASDataUpdatingQueueContext;
- (instancetype)init { - (instancetype)init {
if (self = [super init]) { if (self = [super init]) {
_nodes = [NSMutableArray array]; _nodes = [NSMutableArray array];
_pendingBlocks = [NSMutableArray array];
_batchUpdateCounter = 0; _batchUpdateCounter = 0;
} }
@ -124,63 +109,24 @@ static void *kASDataUpdatingQueueContext = &kASDataUpdatingQueueContext;
return kASSizingQueueContext == dispatch_get_specific(kASSizingQueueContext); return kASSizingQueueContext == dispatch_get_specific(kASSizingQueueContext);
} }
/**
* Concurrent queue for query / updating the cached data.
* The data query is more frequent than the data updating, so we use dispatch_sync for reading, and dispatch_barrier_async for writing.
*/
+ (dispatch_queue_t)dataUpdatingQueue
{
static dispatch_queue_t dataUpdatingQueue = NULL;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
dataUpdatingQueue = dispatch_queue_create("com.facebook.AsyncDisplayKit.ASDataController.dataUpdatingQueue", DISPATCH_QUEUE_CONCURRENT);
dispatch_queue_set_specific(dataUpdatingQueue, kASDataUpdatingQueueContext, kASDataUpdatingQueueContext, NULL);
});
return dataUpdatingQueue;
}
+ (BOOL)isDataUpdatingQueue {
return kASDataUpdatingQueueContext == dispatch_get_specific(kASDataUpdatingQueueContext);
}
- (void)asyncUpdateDataWithBlock:(dispatch_block_t)block { - (void)asyncUpdateDataWithBlock:(dispatch_block_t)block {
#if ENABLE_BACKGROUND_UPDATE
dispatch_barrier_async([ASDataController dataUpdatingQueue], ^{
block();
});
#else
dispatch_async(dispatch_get_main_queue(), ^{ dispatch_async(dispatch_get_main_queue(), ^{
block(); if (_batchUpdateCounter) {
[_pendingBlocks addObject:block];
} else {
block();
}
}); });
#endif
} }
- (void)syncUpdateDataWithBlock:(dispatch_block_t)block { - (void)syncUpdateDataWithBlock:(dispatch_block_t)block {
#if ENABLE_BACKGROUND_UPDATE
dispatch_barrier_sync([ASDataController dataUpdatingQueue], ^{
block();
});
#else
dispatch_sync(dispatch_get_main_queue(), ^{ dispatch_sync(dispatch_get_main_queue(), ^{
block(); if (_batchUpdateCounter) {
}); [_pendingBlocks addObject:block];
#endif } else {
}
- (void)queryDataWithBlock:(dispatch_block_t)block {
#if ENABLE_BACKGROUND_UPDATE
if ([ASDataController isDataUpdatingQueue]) {
block();
} else {
dispatch_sync([ASDataController dataUpdatingQueue], ^{
block(); block();
}); }
} });
#else
ASDisplayNodeAssertMainThread();
block();
#endif
} }
#pragma mark - Initial Data Loading #pragma mark - Initial Data Loading
@ -208,25 +154,39 @@ static void *kASDataUpdatingQueueContext = &kASDataUpdatingQueueContext;
#pragma mark - Data Update #pragma mark - Data Update
- (void)beginUpdates { - (void)beginUpdates
{
dispatch_async([[self class] sizingQueue], ^{ dispatch_async([[self class] sizingQueue], ^{
[self asyncUpdateDataWithBlock:^{ [self asyncUpdateDataWithBlock:^{
_batchUpdateCounter++; _batchUpdateCounter++;
[_delegate dataControllerBeginUpdates:self];
}]; }];
}); });
} }
- (void)endUpdates { - (void)endUpdates {
[self endUpdatesWithCompletion:NULL];
}
- (void)endUpdatesWithCompletion:(void (^)(BOOL))completion
{
dispatch_async([[self class] sizingQueue], ^{ dispatch_async([[self class] sizingQueue], ^{
[self asyncUpdateDataWithBlock:^{ dispatch_async(dispatch_get_main_queue(), ^{
_batchUpdateCounter--; _batchUpdateCounter--;
[_delegate dataControllerEndUpdates:self];
}]; if (!_batchUpdateCounter) {
[_delegate dataControllerBeginUpdates:self];
[_pendingBlocks enumerateObjectsUsingBlock:^(dispatch_block_t block, NSUInteger idx, BOOL *stop) {
block();
}];
[_pendingBlocks removeAllObjects];
[_delegate dataControllerEndUpdates:self completion:completion];
}
});
}); });
} }
- (void)insertSections:(NSIndexSet *)indexSet withAnimationOption:(ASDataControllerAnimationOptions)animationOption { - (void)insertSections:(NSIndexSet *)indexSet withAnimationOption:(ASDataControllerAnimationOptions)animationOption
{
__block int nodeTotalCnt = 0; __block int nodeTotalCnt = 0;
NSMutableArray *nodeCounts = [NSMutableArray arrayWithCapacity:indexSet.count]; NSMutableArray *nodeCounts = [NSMutableArray arrayWithCapacity:indexSet.count];
[indexSet enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL *stop) { [indexSet enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL *stop) {
@ -264,7 +224,8 @@ static void *kASDataUpdatingQueueContext = &kASDataUpdatingQueueContext;
}); });
} }
- (void)deleteSections:(NSIndexSet *)indexSet withAnimationOption:(ASDataControllerAnimationOptions)animationOption { - (void)deleteSections:(NSIndexSet *)indexSet withAnimationOption:(ASDataControllerAnimationOptions)animationOption
{
dispatch_async([[self class] sizingQueue], ^{ dispatch_async([[self class] sizingQueue], ^{
[self asyncUpdateDataWithBlock:^{ [self asyncUpdateDataWithBlock:^{
// remove elements // remove elements
@ -276,7 +237,8 @@ static void *kASDataUpdatingQueueContext = &kASDataUpdatingQueueContext;
}); });
} }
- (void)reloadSections:(NSIndexSet *)sections withAnimationOption:(ASDataControllerAnimationOptions)animationOption { - (void)reloadSections:(NSIndexSet *)sections withAnimationOption:(ASDataControllerAnimationOptions)animationOption
{
// We need to keep data query on data source in the calling thread. // We need to keep data query on data source in the calling thread.
NSMutableArray *updatedIndexPaths = [[NSMutableArray alloc] init]; NSMutableArray *updatedIndexPaths = [[NSMutableArray alloc] init];
NSMutableArray *updatedNodes = [[NSMutableArray alloc] init]; NSMutableArray *updatedNodes = [[NSMutableArray alloc] init];
@ -304,7 +266,8 @@ static void *kASDataUpdatingQueueContext = &kASDataUpdatingQueueContext;
}); });
} }
- (void)moveSection:(NSInteger)section toSection:(NSInteger)newSection withAnimationOption:(ASDataControllerAnimationOptions)animationOption { - (void)moveSection:(NSInteger)section toSection:(NSInteger)newSection withAnimationOption:(ASDataControllerAnimationOptions)animationOption
{
dispatch_async([ASDataController sizingQueue], ^{ dispatch_async([ASDataController sizingQueue], ^{
[self asyncUpdateDataWithBlock:^{ [self asyncUpdateDataWithBlock:^{
// remove elements // remove elements
@ -327,7 +290,8 @@ static void *kASDataUpdatingQueueContext = &kASDataUpdatingQueueContext;
- (void)_insertNodes:(NSArray *)nodes - (void)_insertNodes:(NSArray *)nodes
atIndexPaths:(NSArray *)indexPaths atIndexPaths:(NSArray *)indexPaths
withAnimationOption:(ASDataControllerAnimationOptions)animationOption { withAnimationOption:(ASDataControllerAnimationOptions)animationOption
{
if (!nodes.count) { if (!nodes.count) {
return; return;
} }
@ -369,7 +333,8 @@ static void *kASDataUpdatingQueueContext = &kASDataUpdatingQueueContext;
- (void)_batchInsertNodes:(NSArray *)nodes - (void)_batchInsertNodes:(NSArray *)nodes
atIndexPaths:(NSArray *)indexPaths atIndexPaths:(NSArray *)indexPaths
withAnimationOptions:(ASDataControllerAnimationOptions)animationOption { withAnimationOptions:(ASDataControllerAnimationOptions)animationOption
{
NSUInteger blockSize = [[ASDataController class] parallelProcessorCount] * kASDataControllerSizingCountPerProcessor; NSUInteger blockSize = [[ASDataController class] parallelProcessorCount] * kASDataControllerSizingCountPerProcessor;
// Processing in batches // Processing in batches
@ -382,7 +347,8 @@ static void *kASDataUpdatingQueueContext = &kASDataUpdatingQueueContext;
} }
} }
- (void)insertRowsAtIndexPaths:(NSArray *)indexPaths withAnimationOption:(ASDataControllerAnimationOptions)animationOption { - (void)insertRowsAtIndexPaths:(NSArray *)indexPaths withAnimationOption:(ASDataControllerAnimationOptions)animationOption
{
// sort indexPath to avoid messing up the index when inserting in several batches // sort indexPath to avoid messing up the index when inserting in several batches
NSArray *sortedIndexPaths = [indexPaths sortedArrayUsingSelector:@selector(compare:)]; NSArray *sortedIndexPaths = [indexPaths sortedArrayUsingSelector:@selector(compare:)];
NSMutableArray *nodes = [[NSMutableArray alloc] initWithCapacity:indexPaths.count]; NSMutableArray *nodes = [[NSMutableArray alloc] initWithCapacity:indexPaths.count];
@ -393,7 +359,8 @@ static void *kASDataUpdatingQueueContext = &kASDataUpdatingQueueContext;
[self _batchInsertNodes:nodes atIndexPaths:indexPaths withAnimationOptions:animationOption]; [self _batchInsertNodes:nodes atIndexPaths:indexPaths withAnimationOptions:animationOption];
} }
- (void)deleteRowsAtIndexPaths:(NSArray *)indexPaths withAnimationOption:(ASDataControllerAnimationOptions)animationOption { - (void)deleteRowsAtIndexPaths:(NSArray *)indexPaths withAnimationOption:(ASDataControllerAnimationOptions)animationOption
{
// sort indexPath in order to avoid messing up the index when deleting // sort indexPath in order to avoid messing up the index when deleting
NSArray *sortedIndexPaths = [indexPaths sortedArrayUsingSelector:@selector(compare:)]; NSArray *sortedIndexPaths = [indexPaths sortedArrayUsingSelector:@selector(compare:)];
@ -404,7 +371,8 @@ static void *kASDataUpdatingQueueContext = &kASDataUpdatingQueueContext;
}); });
} }
- (void)reloadRowsAtIndexPaths:(NSArray *)indexPaths withAnimationOption:(ASDataControllerAnimationOptions)animationOption { - (void)reloadRowsAtIndexPaths:(NSArray *)indexPaths withAnimationOption:(ASDataControllerAnimationOptions)animationOption
{
// The reloading operation required reloading the data // The reloading operation required reloading the data
// Loading data in the calling thread // Loading data in the calling thread
NSMutableArray *nodes = [[NSMutableArray alloc] initWithCapacity:indexPaths.count]; NSMutableArray *nodes = [[NSMutableArray alloc] initWithCapacity:indexPaths.count];
@ -422,7 +390,8 @@ static void *kASDataUpdatingQueueContext = &kASDataUpdatingQueueContext;
}); });
} }
- (void)moveRowAtIndexPath:(NSIndexPath *)indexPath toIndexPath:(NSIndexPath *)newIndexPath withAnimationOption:(ASDataControllerAnimationOptions)animationOption { - (void)moveRowAtIndexPath:(NSIndexPath *)indexPath toIndexPath:(NSIndexPath *)newIndexPath withAnimationOption:(ASDataControllerAnimationOptions)animationOption
{
dispatch_async([ASDataController sizingQueue], ^{ dispatch_async([ASDataController sizingQueue], ^{
[self asyncUpdateDataWithBlock:^{ [self asyncUpdateDataWithBlock:^{
NSArray *nodes = ASFindElementsInMultidimensionalArrayAtIndexPaths(_nodes, [NSArray arrayWithObject:indexPath]); NSArray *nodes = ASFindElementsInMultidimensionalArrayAtIndexPaths(_nodes, [NSArray arrayWithObject:indexPath]);
@ -436,7 +405,8 @@ static void *kASDataUpdatingQueueContext = &kASDataUpdatingQueueContext;
}); });
} }
- (void)reloadDataWithAnimationOption:(ASDataControllerAnimationOptions)animationOption { - (void)reloadDataWithAnimationOption:(ASDataControllerAnimationOptions)animationOption
{
// Fetching data in calling thread // Fetching data in calling thread
NSMutableArray *updatedNodes = [[NSMutableArray alloc] init]; NSMutableArray *updatedNodes = [[NSMutableArray alloc] init];
NSMutableArray *updatedIndexPaths = [[NSMutableArray alloc] init]; NSMutableArray *updatedIndexPaths = [[NSMutableArray alloc] init];
@ -480,44 +450,28 @@ static void *kASDataUpdatingQueueContext = &kASDataUpdatingQueueContext;
#pragma mark - Data Querying #pragma mark - Data Querying
- (NSUInteger)numberOfSections { - (NSUInteger)numberOfSections
__block NSUInteger sectionNum; {
ASDisplayNodeAssertMainThread();
[self queryDataWithBlock:^{ return [_nodes count];
sectionNum = [_nodes count];
}];
return sectionNum;
} }
- (NSUInteger)numberOfRowsInSection:(NSUInteger)section { - (NSUInteger)numberOfRowsInSection:(NSUInteger)section
__block NSUInteger rowNum; {
ASDisplayNodeAssertMainThread();
[self queryDataWithBlock:^{ return [_nodes[section] count];
rowNum = [_nodes[section] count];
}];
return rowNum;
} }
- (ASCellNode *)nodeAtIndexPath:(NSIndexPath *)indexPath { - (ASCellNode *)nodeAtIndexPath:(NSIndexPath *)indexPath
__block ASCellNode *node; {
ASDisplayNodeAssertMainThread();
[self queryDataWithBlock:^{ return _nodes[indexPath.section][indexPath.row];
node = _nodes[indexPath.section][indexPath.row];
}];
return node;
} }
- (NSArray *)nodesAtIndexPaths:(NSArray *)indexPaths { - (NSArray *)nodesAtIndexPaths:(NSArray *)indexPaths
__block NSArray *arr = nil; {
ASDisplayNodeAssertMainThread();
[self queryDataWithBlock:^{ return ASFindElementsInMultidimensionalArrayAtIndexPaths(_nodes, indexPaths);
arr = ASFindElementsInMultidimensionalArrayAtIndexPaths(_nodes, indexPaths);
}];
return arr;
} }
@end @end

View File

@ -78,7 +78,7 @@
/** /**
* End updates. * End updates.
*/ */
- (void)rangeControllerEndUpdates:(ASRangeController * )rangeController; - (void)rangeControllerEndUpdates:(ASRangeController * )rangeController completion:(void (^)(BOOL))completion ;
/** /**
* Fetch nodes at specific index paths. * Fetch nodes at specific index paths.

View File

@ -227,9 +227,9 @@
}); });
} }
- (void)dataControllerEndUpdates:(ASDataController *)dataController { - (void)dataControllerEndUpdates:(ASDataController *)dataController completion:(void (^)(BOOL))completion {
ASDisplayNodePerformBlockOnMainThread(^{ ASDisplayNodePerformBlockOnMainThread(^{
[_delegate rangeControllerEndUpdates:self]; [_delegate rangeControllerEndUpdates:self completion:completion];
}); });
} }