Stub out ASCollectionDataController subclass

This commit is contained in:
Levi McCallum 2015-09-22 23:41:43 -07:00 committed by Levi McCallum
parent e492770aed
commit e9eadac4ae
9 changed files with 142 additions and 21 deletions

View File

@ -11,7 +11,7 @@
#import "ASAssert.h"
#import "ASCollectionViewLayoutController.h"
#import "ASRangeController.h"
#import "ASDataController.h"
#import "ASCollectionDataController.h"
#import "ASDisplayNodeInternal.h"
#import "ASBatchFetching.h"
#import "UICollectionViewLayout+ASConvenience.h"
@ -37,9 +37,7 @@ static BOOL _isInterceptedSelector(SEL sel)
// handled by ASCollectionView node<->cell machinery
sel == @selector(collectionView:cellForItemAtIndexPath:) ||
sel == @selector(collectionView:layout:sizeForItemAtIndexPath:) ||
// TODO: Supplementary views are currently not supported. An assertion is triggered if the _asyncDataSource implements this method.
// sel == @selector(collectionView:viewForSupplementaryElementOfKind:atIndexPath:) ||
sel == @selector(collectionView:viewForSupplementaryElementOfKind:atIndexPath:) ||
// handled by ASRangeController
sel == @selector(numberOfSectionsInCollectionView:) ||
@ -136,7 +134,7 @@ static BOOL _isInterceptedSelector(SEL sel)
_ASCollectionViewProxy *_proxyDataSource;
_ASCollectionViewProxy *_proxyDelegate;
ASDataController *_dataController;
ASCollectionDataController *_dataController;
ASRangeController *_rangeController;
ASCollectionViewLayoutController *_layoutController;
@ -201,7 +199,7 @@ static BOOL _isInterceptedSelector(SEL sel)
_rangeController.delegate = self;
_rangeController.layoutController = _layoutController;
_dataController = [[ASDataController alloc] initWithAsyncDataFetching:asyncDataFetchingEnabled];
_dataController = [[ASCollectionDataController alloc] initWithAsyncDataFetching:asyncDataFetchingEnabled];
_dataController.delegate = _rangeController;
_dataController.dataSource = self;
@ -381,8 +379,8 @@ static BOOL _isInterceptedSelector(SEL sel)
- (void)registerSupplementaryViewOfKind:(NSString *)elementKind
{
NSString *identifier = [NSString stringWithFormat:@"_ASCollectionSupplementaryView_%@", elementKind];
[self registerClass:[UIView class] forSupplementaryViewOfKind:elementKind withReuseIdentifier:identifier];
[self registerClass:[UICollectionReusableView class] forSupplementaryViewOfKind:elementKind
withReuseIdentifier:[self __reuseIdentifierForKind:elementKind]];
}
- (void)insertSections:(NSIndexSet *)sections
@ -433,6 +431,16 @@ static BOOL _isInterceptedSelector(SEL sel)
[_dataController moveRowAtIndexPath:indexPath toIndexPath:newIndexPath withAnimationOptions:kASCollectionViewAnimationNone];
}
- (ASCellNode *)nodeForItemAtIndexPath:(NSIndexPath *)indexPath
{
return [_dataController nodeAtIndexPath:indexPath];
}
- (NSString *)__reuseIdentifierForKind:(NSString *)kind
{
return [NSString stringWithFormat:@"_ASCollectionSupplementaryView_%@", kind];
}
#pragma mark -
#pragma mark Intercepted selectors.
@ -443,7 +451,8 @@ static BOOL _isInterceptedSelector(SEL sel)
_ASCollectionViewCell *cell = [self dequeueReusableCellWithReuseIdentifier:reuseIdentifier forIndexPath:indexPath];
ASCellNode *node = [_dataController nodeAtIndexPath:indexPath];
[_rangeController configureContentView:cell.contentView forCellNode:node];
[_rangeController configureContentView:cell.contentView forNode:node];
cell.node = node;
@ -455,6 +464,15 @@ static BOOL _isInterceptedSelector(SEL sel)
return [[_dataController nodeAtIndexPath:indexPath] calculatedSize];
}
- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath
{
NSString *identifier = [self __reuseIdentifierForKind:kind];
UICollectionReusableView *view = [self dequeueReusableSupplementaryViewOfKind:kind withReuseIdentifier:identifier forIndexPath:indexPath];
ASDisplayNode *node = [_dataController supplementaryNodeOfKind:kind atIndexPath:indexPath];
[_rangeController configureContentView:view forNode:node];
return view;
}
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
{
_superIsPendingDataLoad = NO;
@ -613,6 +631,11 @@ static BOOL _isInterceptedSelector(SEL sel)
return node;
}
- (ASDisplayNode *)dataController:(ASDataController *)dataController supplementaryNodeOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath
{
return [_asyncDataSource collectionView:self nodeForSupplementaryElementOfKind:kind atIndexPath:indexPath];
}
- (ASSizeRange)dataController:(ASDataController *)dataController constrainedSizeForNodeAtIndexPath:(NSIndexPath *)indexPath
{
ASSizeRange constrainedSize;
@ -659,7 +682,7 @@ static BOOL _isInterceptedSelector(SEL sel)
return [_asyncDataSource collectionView:self numberOfItemsInSection:section];
}
- (NSUInteger)dataControllerNumberOfSections:(ASDataController *)dataController {
- (NSUInteger)numberOfSectionsInDataController:(ASDataController *)dataController {
if ([_asyncDataSource respondsToSelector:@selector(numberOfSectionsInCollectionView:)]) {
return [_asyncDataSource numberOfSectionsInCollectionView:self];
} else {

View File

@ -530,7 +530,7 @@ void ASPerformBlockWithoutAnimation(BOOL withoutAnimation, void (^block)()) {
}
ASCellNode *node = [_dataController nodeAtIndexPath:indexPath];
[_rangeController configureContentView:cell.contentView forCellNode:node];
[_rangeController configureContentView:cell.contentView forNode:node];
cell.node = node;
cell.backgroundColor = node.backgroundColor;
@ -859,7 +859,7 @@ void ASPerformBlockWithoutAnimation(BOOL withoutAnimation, void (^block)()) {
return [_asyncDataSource tableView:self numberOfRowsInSection:section];
}
- (NSUInteger)dataControllerNumberOfSections:(ASDataController *)dataController
- (NSUInteger)numberOfSectionsInDataController:(ASDataController *)dataController
{
if ([_asyncDataSource respondsToSelector:@selector(numberOfSectionsInTableView:)]) {
return [_asyncDataSource numberOfSectionsInTableView:self];

View File

@ -0,0 +1,26 @@
//
// ASCollectionDataController.h
// Pods
//
// Created by Levi McCallum on 9/22/15.
//
//
#import <AsyncDisplayKit/ASDataController.h>
@class ASDisplayNode, ASCollectionDataController;
@protocol ASDataControllerSource;
@protocol ASCollectionDataControllerSource <ASDataControllerSource>
- (ASDisplayNode *)dataController:(ASDataController *)dataController supplementaryNodeOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath;
- (NSArray *)supplementaryKindsInDataController:(ASCollectionDataController *)dataController;
@end
@interface ASCollectionDataController : ASDataController
- (ASDisplayNode *)supplementaryNodeOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath;
@end

View File

@ -0,0 +1,72 @@
//
// ASCollectionDataController.m
// Pods
//
// Created by Levi McCallum on 9/22/15.
//
//
#import "ASCollectionDataController.h"
#import "ASAssert.h"
@interface ASDataController (Subclasses)
/**
* Queues the given operation until an `endUpdates` synchronize update is completed.
*
* If this method is called outside of a begin/endUpdates batch update, the block is
* executed immediately.
*/
- (void)performEditCommandWithBlock:(void (^)(void))block;
/**
* Safely locks access to the data source and executes the given block, unlocking once complete.
*
* When `asyncDataFetching` is enabled, the block is executed on a background thread.
*/
- (void)accessDataSourceWithBlock:(dispatch_block_t)block;
@end
@implementation ASCollectionDataController {
NSMutableDictionary *_completedSupplementaryNodes;
NSMutableDictionary *_editingSupplementaryNodes;
}
- (void)initialSupplementaryLoading
{
[self performEditCommandWithBlock:^{
ASDisplayNodeAssertMainThread();
[self accessDataSourceWithBlock:^{
NSArray *elementKinds = [self.collectionDataSource supplementaryKindsInDataController:self];
}];
}];
}
- (ASDisplayNode *)supplementaryNodeOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath
{
ASDisplayNodeAssertMainThread();
return _completedSupplementaryNodes[kind][indexPath.section][indexPath.item];
}
- (id<ASCollectionDataControllerSource>)collectionDataSource
{
return (id<ASCollectionDataControllerSource>)self.dataSource;
}
#pragma mark - Internal Data Querying
- (void)_insertNodes:(NSArray *)nodes ofKind:(NSString *)kind atIndexPaths:(NSArray *)indexPaths
{
if (indexPaths.count == 0)
return;
}
- (void)_deleteNodesOfKind:(NSString *)kind atIndexPaths:(NSArray *)indexPaths
{
if (indexPaths.count == 0)
return;
}
@end

View File

@ -40,7 +40,7 @@ typedef NSUInteger ASDataControllerAnimationOptions;
/**
Fetch the number of sections.
*/
- (NSUInteger)dataControllerNumberOfSections:(ASDataController *)dataController;
- (NSUInteger)numberOfSectionsInDataController:(ASDataController *)dataController;
/**
Lock the data source for data fetching.

View File

@ -239,7 +239,7 @@ static void *kASSizingQueueContext = &kASSizingQueueContext;
ASDisplayNodeAssertMainThread();
[self accessDataSourceWithBlock:^{
NSMutableArray *indexPaths = [NSMutableArray array];
NSUInteger sectionNum = [_dataSource dataControllerNumberOfSections:self];
NSUInteger sectionNum = [_dataSource numberOfSectionsInDataController:self];
// insert sections
[self insertSections:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, sectionNum)] withAnimationOptions:0];
@ -266,7 +266,7 @@ static void *kASSizingQueueContext = &kASSizingQueueContext;
[_editingTransactionQueue waitUntilAllOperationsAreFinished];
[self accessDataSourceWithBlock:^{
NSUInteger sectionCount = [_dataSource dataControllerNumberOfSections:self];
NSUInteger sectionCount = [_dataSource numberOfSectionsInDataController:self];
NSMutableArray *updatedNodes = [NSMutableArray array];
NSMutableArray *updatedIndexPaths = [NSMutableArray array];
[self _populateFromEntireDataSourceWithMutableNodes:updatedNodes mutableIndexPaths:updatedIndexPaths];
@ -335,7 +335,7 @@ static void *kASSizingQueueContext = &kASSizingQueueContext;
- (void)_populateFromEntireDataSourceWithMutableNodes:(NSMutableArray *)nodes mutableIndexPaths:(NSMutableArray *)indexPaths
{
NSUInteger sectionNum = [_dataSource dataControllerNumberOfSections:self];
NSUInteger sectionNum = [_dataSource numberOfSectionsInDataController:self];
for (NSUInteger i = 0; i < sectionNum; i++) {
NSIndexPath *sectionIndexPath = [[NSIndexPath alloc] initWithIndex:i];

View File

@ -41,9 +41,9 @@
*
* @param contentView UIView to add a (sized) node's view to.
*
* @param node The ASCellNode to be added.
* @param node The node to be added. Often an ASCellNode.
*/
- (void)configureContentView:(UIView *)contentView forCellNode:(ASCellNode *)node;
- (void)configureContentView:(UIView *)contentView forNode:(ASDisplayNode *)node;
/**
* Delegate and ultimate data source. Must not be nil.

View File

@ -48,7 +48,7 @@
#pragma mark - View manipulation
- (void)moveNode:(ASCellNode *)node toView:(UIView *)view
- (void)moveNode:(ASDisplayNode *)node toView:(UIView *)view
{
ASDisplayNodeAssertMainThread();
ASDisplayNodeAssert(node, @"Cannot move a nil node to a view");
@ -158,7 +158,7 @@
return rangeType == ASLayoutRangeTypeRender;
}
- (void)configureContentView:(UIView *)contentView forCellNode:(ASCellNode *)cellNode
- (void)configureContentView:(UIView *)contentView forNode:(ASDisplayNode *)cellNode
{
if (cellNode.view.superview == contentView) {
// this content view is already correctly configured

View File

@ -64,7 +64,7 @@
// This happens if the UITableViewCell is reused after scrolling offscreen. Because the node has already been given the opportunity to display, we do not
// proactively re-host it within the workingWindow (improving efficiency). Some time later, it may fall outside the working range, in which case calling
// -recursivelyClearContents is critical. If the user scrolls back and it is re-hosted in a UITableViewCell, the content will still exist as it is not cleared
// by simply being removed from the cell. The code that usually triggers this condition is the -removeFromSuperview in -[ASRangeController configureContentView:forCellNode:].
// by simply being removed from the cell. The code that usually triggers this condition is the -removeFromSuperview in -[ASRangeController configureContentView:forNode:].
// Condition #4 is suboptimal in some cases, as it is conceivable that memory warnings could trigger clearing content that is inside the working range. However, enforcing the
// preservation of this content could result in the app being killed, which is not likely preferable over briefly seeing placeholders in the event the user scrolls backwards.
// Nonetheless, future changes to the implementation will likely eliminate this behavior to simplify debugging and extensibility of working range functionality.