Make Cell Node Properties Atomic (#74)

* Make ASCellNode indexPath and supplementaryElementKind atomic

* Update the change log

* Fix licenses

* Be explicit with atomic

* Rename the protocol

* And the file
This commit is contained in:
Adlai Holler 2017-05-02 14:09:12 -07:00 committed by GitHub
parent 471f02daa7
commit a7656766f9
20 changed files with 131 additions and 142 deletions

View File

@ -368,6 +368,7 @@
CCA282D01E9EBF6C0037E8B7 /* ASTipsWindow.h in Headers */ = {isa = PBXBuildFile; fileRef = CCA282CE1E9EBF6C0037E8B7 /* ASTipsWindow.h */; };
CCA282D11E9EBF6C0037E8B7 /* ASTipsWindow.m in Sources */ = {isa = PBXBuildFile; fileRef = CCA282CF1E9EBF6C0037E8B7 /* ASTipsWindow.m */; };
CCB2F34D1D63CCC6004E6DE9 /* ASDisplayNodeSnapshotTests.m in Sources */ = {isa = PBXBuildFile; fileRef = CCB2F34C1D63CCC6004E6DE9 /* ASDisplayNodeSnapshotTests.m */; };
CCBBBF5D1EB161760069AA91 /* ASRangeManagingNode.h in Headers */ = {isa = PBXBuildFile; fileRef = CCBBBF5C1EB161760069AA91 /* ASRangeManagingNode.h */; settings = {ATTRIBUTES = (Public, ); }; };
CCF18FF41D2575E300DF5895 /* NSIndexSet+ASHelpers.h in Headers */ = {isa = PBXBuildFile; fileRef = CC4981BA1D1C7F65004E13CC /* NSIndexSet+ASHelpers.h */; settings = {ATTRIBUTES = (Private, ); }; };
DB55C2671C641AE4004EDCF5 /* ASContextTransitioning.h in Headers */ = {isa = PBXBuildFile; fileRef = DB55C2651C641AE4004EDCF5 /* ASContextTransitioning.h */; settings = {ATTRIBUTES = (Public, ); }; };
DB7121BCD50849C498C886FB /* libPods-AsyncDisplayKitTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = EFA731F0396842FF8AB635EE /* libPods-AsyncDisplayKitTests.a */; };
@ -798,6 +799,7 @@
CCA282CE1E9EBF6C0037E8B7 /* ASTipsWindow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASTipsWindow.h; sourceTree = "<group>"; };
CCA282CF1E9EBF6C0037E8B7 /* ASTipsWindow.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASTipsWindow.m; sourceTree = "<group>"; };
CCB2F34C1D63CCC6004E6DE9 /* ASDisplayNodeSnapshotTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASDisplayNodeSnapshotTests.m; sourceTree = "<group>"; };
CCBBBF5C1EB161760069AA91 /* ASRangeManagingNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASRangeManagingNode.h; sourceTree = "<group>"; };
CCBD05DE1E4147B000D18509 /* ASIGListAdapterBasedDataSource.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASIGListAdapterBasedDataSource.m; sourceTree = "<group>"; };
CCBD05DF1E4147B000D18509 /* ASIGListAdapterBasedDataSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASIGListAdapterBasedDataSource.h; sourceTree = "<group>"; };
CCE04B1E1E313EA7006AEBBB /* ASSectionController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASSectionController.h; sourceTree = "<group>"; };
@ -1002,6 +1004,7 @@
25E327551C16819500A2170C /* ASPagerNode.m */,
A2763D771CBDD57D00A9ADBD /* ASPINRemoteImageDownloader.h */,
A2763D781CBDD57D00A9ADBD /* ASPINRemoteImageDownloader.m */,
CCBBBF5C1EB161760069AA91 /* ASRangeManagingNode.h */,
ACE87A2B1D73696800D7FF06 /* ASSectionContext.h */,
D785F6601A74327E00291744 /* ASScrollNode.h */,
D785F6611A74327E00291744 /* ASScrollNode.mm */,
@ -1533,6 +1536,7 @@
509E68611B3AEDA0009B9150 /* ASAbstractLayoutController.h in Headers */,
CCA282B81E9EA8E40037E8B7 /* AsyncDisplayKit+Tips.h in Headers */,
B35062571B010F070018CF92 /* ASAssert.h in Headers */,
CCBBBF5D1EB161760069AA91 /* ASRangeManagingNode.h in Headers */,
B35062581B010F070018CF92 /* ASAvailability.h in Headers */,
DE84918D1C8FFF2B003D89E9 /* ASRunLoopQueue.h in Headers */,
CC0F88621E4281E200576FED /* ASSectionController.h in Headers */,

View File

@ -5,6 +5,7 @@
- Fix `__has_include` check in ASLog.h [Philipp Smorygo](Philipp.Smorygo@jetbrains.com)
- Fix potential deadlock in ASControlNode [Garrett Moon](https://github.com/garrettmoon)
- [Yoga Beta] Improvements to the experimental support for Yoga layout [Scott Goodson](appleguy)
- Make cell node `indexPath` and `supplementaryElementKind` atomic so you can read from any thread. (Adlai-Holler)[https://github.com/Adlai-Holler] (#49)[https://github.com/TextureGroup/Texture/pull/74]
- Update the rasterization API and un-deprecate it. [Adlai Holler](https://github.com/Adlai-Holler)[#82](https://github.com/TextureGroup/Texture/pull/49)
- Simplified & optimized hashing code. [Adlai Holler](https://github.com/Adlai-Holler) [#86](https://github.com/TextureGroup/Texture/pull/86)
- Improve the performance & safety of ASDisplayNode subnodes. [Adlai Holler](https://github.com/Adlai-Holler) [#223](https://github.com/TextureGroup/Texture/pull/223)

View File

@ -20,6 +20,7 @@
NS_ASSUME_NONNULL_BEGIN
@class ASCellNode, ASTextNode;
@protocol ASRangeManagingNode;
typedef NSUInteger ASCellNodeAnimation;
@ -87,7 +88,7 @@ typedef NS_ENUM(NSUInteger, ASCellNodeVisibilityEvent) {
* @return The supplementary element kind, or @c nil if this node does not represent a supplementary element.
*/
//TODO change this to be a generic "kind" or "elementKind" that exposes `nil` for row kind
@property (nonatomic, copy, readonly, nullable) NSString *supplementaryElementKind;
@property (atomic, copy, readonly, nullable) NSString *supplementaryElementKind;
/*
* The layout attributes currently assigned to this node, if any.
@ -113,10 +114,8 @@ typedef NS_ENUM(NSUInteger, ASCellNodeVisibilityEvent) {
/**
* The current index path of this cell node, or @c nil if this node is
* not a valid item inside a table node or collection node.
*
* @note This property must be accessed on the main thread.
*/
@property (nonatomic, readonly, nullable) NSIndexPath *indexPath;
@property (atomic, readonly, nullable) NSIndexPath *indexPath;
/**
* The backing view controller, or @c nil if the node wasn't initialized with backing view controller
@ -126,10 +125,9 @@ typedef NS_ENUM(NSUInteger, ASCellNodeVisibilityEvent) {
/**
* The owning node (ASCollectionNode/ASTableNode) of this cell node, or @c nil if this node is
* not a valid item inside a table node or collection node or if those nodes are nil.
* The table- or collection-node that this cell is a member of, if any.
*/
@property (weak, nonatomic, readonly, nullable) ASDisplayNode *owningNode;
@property (atomic, weak, readonly, nullable) id<ASRangeManagingNode> owningNode;
/*
* ASCellNode must forward touch events in order for UITableView and UICollectionView tap handling to work. Overriding

View File

@ -44,12 +44,6 @@
ASDisplayNode *_viewControllerNode;
UIViewController *_viewController;
BOOL _suspendInteractionDelegate;
struct {
unsigned int isTableNode:1;
unsigned int isCollectionNode:1;
} _owningNodeType;
}
@end
@ -165,19 +159,6 @@
}
}
- (void)setOwningNode:(ASDisplayNode *)owningNode
{
_owningNode = owningNode;
memset(&_owningNodeType, 0, sizeof(_owningNodeType));
if ([owningNode isKindOfClass:[ASTableNode class]]) {
_owningNodeType.isTableNode = 1;
} else if ([owningNode isKindOfClass:[ASCollectionNode class]]) {
_owningNodeType.isCollectionNode = 1;
}
}
- (void)__setSelectedFromUIKit:(BOOL)selected;
{
if (selected != _selected) {
@ -198,15 +179,7 @@
- (NSIndexPath *)indexPath
{
ASDisplayNodeAssertMainThread();
if (_owningNodeType.isTableNode) {
return [(ASTableNode *)self.owningNode indexPathForNode:self];
} else if (_owningNodeType.isCollectionNode) {
return [(ASCollectionNode *)self.owningNode indexPathForNode:self];
}
return nil;
return [self.owningNode indexPathForNode:self];
}
- (UIViewController *)viewController

View File

@ -20,6 +20,7 @@
#import <AsyncDisplayKit/ASRangeControllerUpdateRangeProtocol+Beta.h>
#import <AsyncDisplayKit/ASCollectionView.h>
#import <AsyncDisplayKit/ASBlockTypes.h>
#import <AsyncDisplayKit/ASRangeManagingNode.h>
@protocol ASCollectionViewLayoutFacilitatorProtocol;
@protocol ASCollectionDelegate;
@ -32,7 +33,7 @@ NS_ASSUME_NONNULL_BEGIN
* ASCollectionNode is a node based class that wraps an ASCollectionView. It can be used
* as a subnode of another node, and provide room for many (great) features and improvements later on.
*/
@interface ASCollectionNode : ASDisplayNode <ASRangeControllerUpdateRangeProtocol>
@interface ASCollectionNode : ASDisplayNode <ASRangeControllerUpdateRangeProtocol, ASRangeManagingNode>
- (instancetype)init NS_UNAVAILABLE;

View File

@ -155,7 +155,7 @@
__weak __typeof__(self) weakSelf = self;
[self setViewBlock:^{
__typeof__(self) strongSelf = weakSelf;
return [[[strongSelf collectionViewClass] alloc] _initWithFrame:frame collectionViewLayout:strongSelf->_pendingState.collectionViewLayout layoutFacilitator:layoutFacilitator eventLog:ASDisplayNodeGetEventLog(strongSelf)];
return [[[strongSelf collectionViewClass] alloc] _initWithFrame:frame collectionViewLayout:strongSelf->_pendingState.collectionViewLayout layoutFacilitator:layoutFacilitator owningNode:strongSelf eventLog:ASDisplayNodeGetEventLog(strongSelf)];
}];
}
return self;

View File

@ -80,7 +80,7 @@ static NSString * const kReuseIdentifier = @"_ASCollectionReuseIdentifier";
#pragma mark -
#pragma mark ASCollectionView.
@interface ASCollectionView () <ASRangeControllerDataSource, ASRangeControllerDelegate, ASDataControllerSource, ASCellNodeInteractionDelegate, ASDelegateProxyInterceptor, ASBatchFetchingScrollView, ASDataControllerEnvironmentDelegate, ASCALayerExtendedDelegate, UICollectionViewDelegateFlowLayout> {
@interface ASCollectionView () <ASRangeControllerDataSource, ASRangeControllerDelegate, ASDataControllerSource, ASCellNodeInteractionDelegate, ASDelegateProxyInterceptor, ASBatchFetchingScrollView, ASCALayerExtendedDelegate, UICollectionViewDelegateFlowLayout> {
ASCollectionViewProxy *_proxyDataSource;
ASCollectionViewProxy *_proxyDelegate;
@ -250,10 +250,10 @@ static NSString * const kReuseIdentifier = @"_ASCollectionReuseIdentifier";
- (instancetype)initWithFrame:(CGRect)frame collectionViewLayout:(UICollectionViewLayout *)layout
{
return [self _initWithFrame:frame collectionViewLayout:layout layoutFacilitator:nil eventLog:nil];
return [self _initWithFrame:frame collectionViewLayout:layout layoutFacilitator:nil owningNode:nil eventLog:nil];
}
- (instancetype)_initWithFrame:(CGRect)frame collectionViewLayout:(UICollectionViewLayout *)layout layoutFacilitator:(id<ASCollectionViewLayoutFacilitatorProtocol>)layoutFacilitator eventLog:(ASEventLog *)eventLog
- (instancetype)_initWithFrame:(CGRect)frame collectionViewLayout:(UICollectionViewLayout *)layout layoutFacilitator:(id<ASCollectionViewLayoutFacilitatorProtocol>)layoutFacilitator owningNode:(ASCollectionNode *)owningNode eventLog:(ASEventLog *)eventLog
{
if (!(self = [super initWithFrame:frame collectionViewLayout:layout]))
return nil;
@ -273,9 +273,8 @@ static NSString * const kReuseIdentifier = @"_ASCollectionReuseIdentifier";
_rangeController.delegate = self;
_rangeController.layoutController = _layoutController;
_dataController = [[ASDataController alloc] initWithDataSource:self eventLog:eventLog];
_dataController = [[ASDataController alloc] initWithDataSource:self node:owningNode eventLog:eventLog];
_dataController.delegate = _rangeController;
_dataController.environmentDelegate = self;
_batchContext = [[ASBatchContext alloc] init];
@ -1649,11 +1648,6 @@ static NSString * const kReuseIdentifier = @"_ASCollectionReuseIdentifier";
}
- (id<ASTraitEnvironment>)dataControllerEnvironment
{
return self.collectionNode;
}
#pragma mark - ASDataControllerSource optional methods
- (ASCellNodeBlock)dataController:(ASDataController *)dataController supplementaryNodeBlockOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath

View File

@ -0,0 +1,35 @@
//
// ASRangeManagingNode.h
// Texture
//
// Copyright (c) 2017-present, Pinterest, Inc. All rights reserved.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
#import <Foundation/Foundation.h>
#import <AsyncDisplayKit/ASTraitCollection.h>
@class ASCellNode;
NS_ASSUME_NONNULL_BEGIN
/**
* Basically ASTableNode or ASCollectionNode.
*/
@protocol ASRangeManagingNode <NSObject, ASTraitEnvironment>
/**
* Retrieve the index path for the given node, if it's a member of this container.
*
* @param node The node.
* @return The index path, or nil if the node is not part of this container.
*/
- (nullable NSIndexPath *)indexPathForNode:(ASCellNode *)node;
@end
NS_ASSUME_NONNULL_END

View File

@ -19,7 +19,7 @@
#import <AsyncDisplayKit/ASDisplayNode.h>
#import <AsyncDisplayKit/ASRangeControllerUpdateRangeProtocol+Beta.h>
#import <AsyncDisplayKit/ASTableView.h>
#import <AsyncDisplayKit/ASRangeManagingNode.h>
NS_ASSUME_NONNULL_BEGIN
@ -31,7 +31,7 @@ NS_ASSUME_NONNULL_BEGIN
* ASTableNode is a node based class that wraps an ASTableView. It can be used
* as a subnode of another node, and provide room for many (great) features and improvements later on.
*/
@interface ASTableNode : ASDisplayNode <ASRangeControllerUpdateRangeProtocol>
@interface ASTableNode : ASDisplayNode <ASRangeControllerUpdateRangeProtocol, ASRangeManagingNode>
- (instancetype)init; // UITableViewStylePlain
- (instancetype)initWithStyle:(UITableViewStyle)style NS_DESIGNATED_INITIALIZER;

View File

@ -80,7 +80,7 @@
[self setViewBlock:^{
// Variable will be unused if event logging is off.
__unused __typeof__(self) strongSelf = weakSelf;
return [[ASTableView alloc] _initWithFrame:CGRectZero style:style dataControllerClass:nil eventLog:ASDisplayNodeGetEventLog(strongSelf)];
return [[ASTableView alloc] _initWithFrame:CGRectZero style:style dataControllerClass:nil owningNode:strongSelf eventLog:ASDisplayNodeGetEventLog(strongSelf)];
}];
}
return self;

View File

@ -147,7 +147,7 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell";
#pragma mark -
#pragma mark ASTableView
@interface ASTableView () <ASRangeControllerDataSource, ASRangeControllerDelegate, ASDataControllerSource, _ASTableViewCellDelegate, ASCellNodeInteractionDelegate, ASDelegateProxyInterceptor, ASBatchFetchingScrollView, ASDataControllerEnvironmentDelegate>
@interface ASTableView () <ASRangeControllerDataSource, ASRangeControllerDelegate, ASDataControllerSource, _ASTableViewCellDelegate, ASCellNodeInteractionDelegate, ASDelegateProxyInterceptor, ASBatchFetchingScrollView>
{
ASTableViewProxy *_proxyDataSource;
ASTableViewProxy *_proxyDelegate;
@ -286,8 +286,22 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell";
#pragma mark -
#pragma mark Lifecycle
- (void)configureWithDataControllerClass:(Class)dataControllerClass eventLog:(ASEventLog *)eventLog
- (instancetype)initWithFrame:(CGRect)frame style:(UITableViewStyle)style
{
return [self _initWithFrame:frame style:style dataControllerClass:nil owningNode:nil eventLog:nil];
}
- (instancetype)_initWithFrame:(CGRect)frame style:(UITableViewStyle)style dataControllerClass:(Class)dataControllerClass owningNode:(ASTableNode *)tableNode eventLog:(ASEventLog *)eventLog
{
if (!(self = [super initWithFrame:frame style:style])) {
return nil;
}
_cellsForVisibilityUpdates = [NSMutableSet set];
_cellsForLayoutUpdates = [NSMutableSet set];
if (!dataControllerClass) {
dataControllerClass = [[self class] dataControllerClass];
}
_layoutController = [[ASTableLayoutController alloc] initWithTableView:self];
_rangeController = [[ASRangeController alloc] init];
@ -295,13 +309,12 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell";
_rangeController.dataSource = self;
_rangeController.delegate = self;
_dataController = [[dataControllerClass alloc] initWithDataSource:self eventLog:eventLog];
_dataController = [[dataControllerClass alloc] initWithDataSource:self node:tableNode eventLog:eventLog];
_dataController.delegate = _rangeController;
_dataController.environmentDelegate = self;
_leadingScreensForBatching = 2.0;
_batchContext = [[ASBatchContext alloc] init];
_automaticallyAdjustsContentOffset = NO;
_nodesConstrainedWidth = self.bounds.size.width;
@ -313,25 +326,6 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell";
super.dataSource = (id<UITableViewDataSource>)_proxyDataSource;
[self registerClass:_ASTableViewCell.class forCellReuseIdentifier:kCellReuseIdentifier];
}
- (instancetype)initWithFrame:(CGRect)frame style:(UITableViewStyle)style
{
return [self _initWithFrame:frame style:style dataControllerClass:nil eventLog:nil];
}
- (instancetype)_initWithFrame:(CGRect)frame style:(UITableViewStyle)style dataControllerClass:(Class)dataControllerClass eventLog:(ASEventLog *)eventLog
{
if (!(self = [super initWithFrame:frame style:style])) {
return nil;
}
_cellsForVisibilityUpdates = [NSMutableSet set];
_cellsForLayoutUpdates = [NSMutableSet set];
if (!dataControllerClass) {
dataControllerClass = [[self class] dataControllerClass];
}
[self configureWithDataControllerClass:dataControllerClass eventLog:eventLog];
if (!AS_AT_LEAST_IOS9) {
_retainedLayer = self.layer;
@ -1734,13 +1728,6 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell";
return (fabs(rect.size.height - size.height) < FLT_EPSILON);
}
#pragma mark - ASDataControllerEnvironmentDelegate
- (id<ASTraitEnvironment>)dataControllerEnvironment
{
return self.tableNode;
}
#pragma mark - _ASTableViewCellDelegate
- (void)didLayoutSubviewsOfTableViewCell:(_ASTableViewCell *)tableViewCell

View File

@ -40,7 +40,7 @@
*
* @param eventLog An event log passed through to the data controller.
*/
- (instancetype)_initWithFrame:(CGRect)frame style:(UITableViewStyle)style dataControllerClass:(Class)dataControllerClass eventLog:(ASEventLog *)eventLog;
- (instancetype)_initWithFrame:(CGRect)frame style:(UITableViewStyle)style dataControllerClass:(Class)dataControllerClass owningNode:(ASTableNode *)tableNode eventLog:(ASEventLog *)eventLog;
/// Set YES and we'll log every time we call [super insertRows…] etc
@property (nonatomic) BOOL test_enableSuperUpdateCallLogging;

View File

@ -43,6 +43,7 @@
#import <AsyncDisplayKit/ASCollectionViewLayoutInspector.h>
#import <AsyncDisplayKit/ASCollectionViewLayoutFacilitatorProtocol.h>
#import <AsyncDisplayKit/ASCellNode.h>
#import <AsyncDisplayKit/ASRangeManagingNode.h>
#import <AsyncDisplayKit/ASSectionContext.h>
#import <AsyncDisplayKit/ASElementMap.h>

View File

@ -19,6 +19,7 @@
#import <AsyncDisplayKit/ASTraitCollection.h>
@class ASDisplayNode;
@protocol ASRangeManagingNode;
NS_ASSUME_NONNULL_BEGIN
@ -28,13 +29,13 @@ AS_SUBCLASSING_RESTRICTED
//TODO change this to be a generic "kind" or "elementKind" that exposes `nil` for row kind
@property (nonatomic, readonly, copy, nullable) NSString *supplementaryElementKind;
@property (nonatomic, assign) ASSizeRange constrainedSize;
@property (nonatomic, weak) ASDisplayNode *owningNode;
@property (nonatomic, readonly, weak) id<ASRangeManagingNode> owningNode;
@property (nonatomic, assign) ASPrimitiveTraitCollection traitCollection;
- (instancetype)initWithNodeBlock:(ASCellNodeBlock)nodeBlock
supplementaryElementKind:(nullable NSString *)supplementaryElementKind
constrainedSize:(ASSizeRange)constrainedSize
owningNode:(ASDisplayNode *)owningNode
owningNode:(id<ASRangeManagingNode>)owningNode
traitCollection:(ASPrimitiveTraitCollection)traitCollection;
/**

View File

@ -34,7 +34,7 @@
- (instancetype)initWithNodeBlock:(ASCellNodeBlock)nodeBlock
supplementaryElementKind:(NSString *)supplementaryElementKind
constrainedSize:(ASSizeRange)constrainedSize
owningNode:(ASDisplayNode *)owningNode
owningNode:(id<ASRangeManagingNode>)owningNode
traitCollection:(ASPrimitiveTraitCollection)traitCollection
{
NSAssert(nodeBlock != nil, @"Node block must not be nil");

View File

@ -25,7 +25,7 @@ NS_ASSUME_NONNULL_BEGIN
@class ASRangeController;
@interface ASCollectionView ()
- (instancetype)_initWithFrame:(CGRect)frame collectionViewLayout:(UICollectionViewLayout *)layout layoutFacilitator:(nullable id<ASCollectionViewLayoutFacilitatorProtocol>)layoutFacilitator eventLog:(nullable ASEventLog *)eventLog;
- (instancetype)_initWithFrame:(CGRect)frame collectionViewLayout:(UICollectionViewLayout *)layout layoutFacilitator:(nullable id<ASCollectionViewLayoutFacilitatorProtocol>)layoutFacilitator owningNode:(nullable ASCollectionNode *)owningNode eventLog:(nullable ASEventLog *)eventLog;
@property (nonatomic, weak, readwrite) ASCollectionNode *collectionNode;
@property (nonatomic, strong, readonly) ASDataController *dataController;

View File

@ -39,6 +39,7 @@ NS_ASSUME_NONNULL_BEGIN
@class ASElementMap;
@class ASLayout;
@class _ASHierarchyChangeSet;
@protocol ASRangeManagingNode;
@protocol ASTraitEnvironment;
@protocol ASSectionContext;
@ -96,12 +97,6 @@ extern NSString * const ASCollectionInvalidUpdateException;
@end
@protocol ASDataControllerEnvironmentDelegate
- (nullable id<ASTraitEnvironment>)dataControllerEnvironment;
@end
/**
Delegate for notify the data updating of data controller.
These methods will be invoked from main thread right now, but it may be moved to background thread in the future.
@ -160,17 +155,30 @@ extern NSString * const ASCollectionInvalidUpdateException;
*/
@interface ASDataController : NSObject
- (instancetype)initWithDataSource:(id<ASDataControllerSource>)dataSource eventLog:(nullable ASEventLog *)eventLog NS_DESIGNATED_INITIALIZER;
- (instancetype)initWithDataSource:(id<ASDataControllerSource>)dataSource node:(nullable id<ASRangeManagingNode>)node eventLog:(nullable ASEventLog *)eventLog NS_DESIGNATED_INITIALIZER;
- (instancetype)init NS_UNAVAILABLE;
/**
* The node that owns this data controller, if any.
*
* NOTE: Soon we will drop support for using ASTableView/ASCollectionView without the node, so this will be non-null.
*/
@property (nonatomic, nullable, weak, readonly) id<ASRangeManagingNode> node;
/**
* The map that is currently displayed. The "UIKit index space."
*
* This property will only be changed on the main thread.
*/
@property (nonatomic, strong, readonly) ASElementMap *visibleMap;
@property (atomic, copy, readonly) ASElementMap *visibleMap;
/**
* The latest map fetched from the data source. May be more recent than @c visibleMap.
*
* This property will only be changed on the main thread.
*/
@property (nonatomic, strong, readonly) ASElementMap *pendingMap;
@property (atomic, copy, readonly) ASElementMap *pendingMap;
/**
Data source for fetching data info.
@ -187,11 +195,6 @@ extern NSString * const ASCollectionInvalidUpdateException;
*/
@property (nonatomic, weak) id<ASDataControllerDelegate> delegate;
/**
*
*/
@property (nonatomic, weak) id<ASDataControllerEnvironmentDelegate> environmentDelegate;
/**
* Delegate for preparing layouts. Main thead only.
*/

View File

@ -27,6 +27,7 @@
#import <AsyncDisplayKit/ASLayout.h>
#import <AsyncDisplayKit/ASMainSerialQueue.h>
#import <AsyncDisplayKit/ASMutableElementMap.h>
#import <AsyncDisplayKit/ASRangeManagingNode.h>
#import <AsyncDisplayKit/ASThread.h>
#import <AsyncDisplayKit/ASTwoDimensionalArrayUtils.h>
#import <AsyncDisplayKit/ASSection.h>
@ -85,18 +86,21 @@ typedef void (^ASDataControllerCompletionBlock)(NSArray<ASCollectionElement *> *
} _dataSourceFlags;
}
@property (atomic, copy, readwrite) ASElementMap *pendingMap;
@property (atomic, copy, readwrite) ASElementMap *visibleMap;
@end
@implementation ASDataController
#pragma mark - Lifecycle
- (instancetype)initWithDataSource:(id<ASDataControllerSource>)dataSource eventLog:(ASEventLog *)eventLog
- (instancetype)initWithDataSource:(id<ASDataControllerSource>)dataSource node:(nullable id<ASRangeManagingNode>)node eventLog:(ASEventLog *)eventLog
{
if (!(self = [super init])) {
return nil;
}
_node = node;
_dataSource = dataSource;
_dataSourceFlags.supplementaryNodeKindsInSections = [_dataSource respondsToSelector:@selector(dataController:supplementaryNodeKindsInSections:)];
@ -110,7 +114,7 @@ typedef void (^ASDataControllerCompletionBlock)(NSArray<ASCollectionElement *> *
_eventLog = eventLog;
#endif
_visibleMap = _pendingMap = [[ASElementMap alloc] init];
self.visibleMap = self.pendingMap = [[ASElementMap alloc] init];
_nextSectionID = 0;
@ -124,14 +128,6 @@ typedef void (^ASDataControllerCompletionBlock)(NSArray<ASCollectionElement *> *
return self;
}
- (instancetype)init
{
ASDisplayNodeFailAssert(@"Failed to call designated initializer.");
id<ASDataControllerSource> fakeDataSource = nil;
ASEventLog *eventLog = nil;
return [self initWithDataSource:fakeDataSource eventLog:eventLog];
}
+ (NSUInteger)parallelProcessorCount
{
static NSUInteger parallelProcessorCount;
@ -277,9 +273,10 @@ typedef void (^ASDataControllerCompletionBlock)(NSArray<ASCollectionElement *> *
}
}];
} else if (_dataSourceFlags.supplementaryNodesOfKindInSection) {
id<ASDataControllerSource> dataSource = _dataSource;
[sections enumerateRangesUsingBlock:^(NSRange range, BOOL * _Nonnull stop) {
for (NSUInteger sectionIndex = range.location; sectionIndex < NSMaxRange(range); sectionIndex++) {
NSUInteger itemCount = [_dataSource dataController:self supplementaryNodesOfKind:kind inSection:sectionIndex];
NSUInteger itemCount = [dataSource dataController:self supplementaryNodesOfKind:kind inSection:sectionIndex];
for (NSUInteger i = 0; i < itemCount; i++) {
[indexPaths addObject:[NSIndexPath indexPathForItem:i inSection:sectionIndex]];
}
@ -296,7 +293,6 @@ typedef void (^ASDataControllerCompletionBlock)(NSArray<ASCollectionElement *> *
* @param map The element map into which to apply the change.
* @param indexPaths The index paths belongs to sections whose supplementary nodes need to be repopulated.
* @param changeSet The changeset that triggered this repopulation.
* @param owningNode The node that owns the new elements.
* @param traitCollection The trait collection needed to initialize elements
* @param indexPathsAreNew YES if index paths are "after the update," NO otherwise.
* @param shouldFetchSizeRanges Whether constrained sizes should be fetched from data source
@ -304,7 +300,6 @@ typedef void (^ASDataControllerCompletionBlock)(NSArray<ASCollectionElement *> *
- (void)_repopulateSupplementaryNodesIntoMap:(ASMutableElementMap *)map
forSectionsContainingIndexPaths:(NSArray<NSIndexPath *> *)indexPaths
changeSet:(_ASHierarchyChangeSet *)changeSet
owningNode:(ASDisplayNode *)owningNode
traitCollection:(ASPrimitiveTraitCollection)traitCollection
indexPathsAreNew:(BOOL)indexPathsAreNew
shouldFetchSizeRanges:(BOOL)shouldFetchSizeRanges
@ -330,7 +325,7 @@ typedef void (^ASDataControllerCompletionBlock)(NSArray<ASCollectionElement *> *
}
for (NSString *kind in [self supplementaryKindsInSections:newSections]) {
[self _insertElementsIntoMap:map kind:kind forSections:newSections owningNode:owningNode traitCollection:traitCollection shouldFetchSizeRanges:shouldFetchSizeRanges];
[self _insertElementsIntoMap:map kind:kind forSections:newSections traitCollection:traitCollection shouldFetchSizeRanges:shouldFetchSizeRanges];
}
}
@ -346,7 +341,6 @@ typedef void (^ASDataControllerCompletionBlock)(NSArray<ASCollectionElement *> *
- (void)_insertElementsIntoMap:(ASMutableElementMap *)map
kind:(NSString *)kind
forSections:(NSIndexSet *)sections
owningNode:(ASDisplayNode *)owningNode
traitCollection:(ASPrimitiveTraitCollection)traitCollection
shouldFetchSizeRanges:(BOOL)shouldFetchSizeRanges
{
@ -357,7 +351,7 @@ typedef void (^ASDataControllerCompletionBlock)(NSArray<ASCollectionElement *> *
}
NSArray<NSIndexPath *> *indexPaths = [self _allIndexPathsForItemsOfKind:kind inSections:sections];
[self _insertElementsIntoMap:map kind:kind atIndexPaths:indexPaths owningNode:owningNode traitCollection:traitCollection shouldFetchSizeRanges:shouldFetchSizeRanges];
[self _insertElementsIntoMap:map kind:kind atIndexPaths:indexPaths traitCollection:traitCollection shouldFetchSizeRanges:shouldFetchSizeRanges];
}
/**
@ -373,7 +367,6 @@ typedef void (^ASDataControllerCompletionBlock)(NSArray<ASCollectionElement *> *
- (void)_insertElementsIntoMap:(ASMutableElementMap *)map
kind:(NSString *)kind
atIndexPaths:(NSArray<NSIndexPath *> *)indexPaths
owningNode:(ASDisplayNode *)owningNode
traitCollection:(ASPrimitiveTraitCollection)traitCollection
shouldFetchSizeRanges:(BOOL)shouldFetchSizeRanges
{
@ -390,12 +383,14 @@ typedef void (^ASDataControllerCompletionBlock)(NSArray<ASCollectionElement *> *
}
LOG(@"Populating elements of kind: %@, for index paths: %@", kind, indexPaths);
id<ASDataControllerSource> dataSource = self.dataSource;
id<ASRangeManagingNode> node = self.node;
for (NSIndexPath *indexPath in indexPaths) {
ASCellNodeBlock nodeBlock;
if (isRowKind) {
nodeBlock = [_dataSource dataController:self nodeBlockAtIndexPath:indexPath];
nodeBlock = [dataSource dataController:self nodeBlockAtIndexPath:indexPath];
} else {
nodeBlock = [_dataSource dataController:self supplementaryNodeBlockOfKind:kind atIndexPath:indexPath];
nodeBlock = [dataSource dataController:self supplementaryNodeBlockOfKind:kind atIndexPath:indexPath];
}
ASSizeRange constrainedSize;
@ -406,7 +401,7 @@ typedef void (^ASDataControllerCompletionBlock)(NSArray<ASCollectionElement *> *
ASCollectionElement *element = [[ASCollectionElement alloc] initWithNodeBlock:nodeBlock
supplementaryElementKind:isRowKind ? nil : kind
constrainedSize:constrainedSize
owningNode:owningNode
owningNode:node
traitCollection:traitCollection];
[map insertElement:element atIndexPath:indexPath];
}
@ -544,14 +539,12 @@ typedef void (^ASDataControllerCompletionBlock)(NSArray<ASCollectionElement *> *
// Step 1: Update the mutable copies to match the data source's state
[self _updateSectionContextsInMap:mutableMap changeSet:changeSet];
__weak id<ASTraitEnvironment> environment = [self.environmentDelegate dataControllerEnvironment];
__weak ASDisplayNode *owningNode = (ASDisplayNode *)environment; // This is gross!
ASPrimitiveTraitCollection existingTraitCollection = [environment primitiveTraitCollection];
[self _updateElementsInMap:mutableMap changeSet:changeSet owningNode:owningNode traitCollection:existingTraitCollection shouldFetchSizeRanges:(! canDelegateLayout)];
ASPrimitiveTraitCollection existingTraitCollection = [self.node primitiveTraitCollection];
[self _updateElementsInMap:mutableMap changeSet:changeSet traitCollection:existingTraitCollection shouldFetchSizeRanges:(! canDelegateLayout)];
// Step 2: Clone the new data
ASElementMap *newMap = [mutableMap copy];
_pendingMap = newMap;
self.pendingMap = newMap;
// Step 3: Ask layout delegate for contexts
id layoutContext = nil;
@ -585,7 +578,7 @@ typedef void (^ASDataControllerCompletionBlock)(NSArray<ASCollectionElement *> *
[_delegate dataController:self willUpdateWithChangeSet:changeSet];
// Step 5: Deploy the new data as "completed" and inform delegate
_visibleMap = newMap;
self.visibleMap = newMap;
[_delegate dataController:self didUpdateWithChangeSet:changeSet];
}];
@ -644,7 +637,6 @@ typedef void (^ASDataControllerCompletionBlock)(NSArray<ASCollectionElement *> *
*/
- (void)_updateElementsInMap:(ASMutableElementMap *)map
changeSet:(_ASHierarchyChangeSet *)changeSet
owningNode:(ASDisplayNode *)owningNode
traitCollection:(ASPrimitiveTraitCollection)traitCollection
shouldFetchSizeRanges:(BOOL)shouldFetchSizeRanges
{
@ -656,7 +648,7 @@ typedef void (^ASDataControllerCompletionBlock)(NSArray<ASCollectionElement *> *
NSUInteger sectionCount = [self itemCountsFromDataSource].size();
if (sectionCount > 0) {
NSIndexSet *sectionIndexes = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, sectionCount)];
[self _insertElementsIntoMap:map sections:sectionIndexes owningNode:owningNode traitCollection:traitCollection shouldFetchSizeRanges:shouldFetchSizeRanges];
[self _insertElementsIntoMap:map sections:sectionIndexes traitCollection:traitCollection shouldFetchSizeRanges:shouldFetchSizeRanges];
}
// Return immediately because reloadData can't be used in conjuntion with other updates.
return;
@ -667,7 +659,6 @@ typedef void (^ASDataControllerCompletionBlock)(NSArray<ASCollectionElement *> *
// Aggressively repopulate supplementary nodes (#1773 & #1629)
[self _repopulateSupplementaryNodesIntoMap:map forSectionsContainingIndexPaths:change.indexPaths
changeSet:changeSet
owningNode:owningNode
traitCollection:traitCollection
indexPathsAreNew:NO
shouldFetchSizeRanges:shouldFetchSizeRanges];
@ -680,15 +671,14 @@ typedef void (^ASDataControllerCompletionBlock)(NSArray<ASCollectionElement *> *
}
for (_ASHierarchySectionChange *change in [changeSet sectionChangesOfType:_ASHierarchyChangeTypeInsert]) {
[self _insertElementsIntoMap:map sections:change.indexSet owningNode:owningNode traitCollection:traitCollection shouldFetchSizeRanges:shouldFetchSizeRanges];
[self _insertElementsIntoMap:map sections:change.indexSet traitCollection:traitCollection shouldFetchSizeRanges:shouldFetchSizeRanges];
}
for (_ASHierarchyItemChange *change in [changeSet itemChangesOfType:_ASHierarchyChangeTypeInsert]) {
[self _insertElementsIntoMap:map kind:ASDataControllerRowNodeKind atIndexPaths:change.indexPaths owningNode:owningNode traitCollection:traitCollection shouldFetchSizeRanges:shouldFetchSizeRanges];
[self _insertElementsIntoMap:map kind:ASDataControllerRowNodeKind atIndexPaths:change.indexPaths traitCollection:traitCollection shouldFetchSizeRanges:shouldFetchSizeRanges];
// Aggressively reload supplementary nodes (#1773 & #1629)
[self _repopulateSupplementaryNodesIntoMap:map forSectionsContainingIndexPaths:change.indexPaths
changeSet:changeSet
owningNode:owningNode
traitCollection:traitCollection
indexPathsAreNew:YES
shouldFetchSizeRanges:shouldFetchSizeRanges];
@ -697,7 +687,6 @@ typedef void (^ASDataControllerCompletionBlock)(NSArray<ASCollectionElement *> *
- (void)_insertElementsIntoMap:(ASMutableElementMap *)map
sections:(NSIndexSet *)sectionIndexes
owningNode:(ASDisplayNode *)owningNode
traitCollection:(ASPrimitiveTraitCollection)traitCollection
shouldFetchSizeRanges:(BOOL)shouldFetchSizeRanges
{
@ -709,12 +698,12 @@ typedef void (^ASDataControllerCompletionBlock)(NSArray<ASCollectionElement *> *
// Items
[map insertEmptySectionsOfItemsAtIndexes:sectionIndexes];
[self _insertElementsIntoMap:map kind:ASDataControllerRowNodeKind forSections:sectionIndexes owningNode:owningNode traitCollection:traitCollection shouldFetchSizeRanges:shouldFetchSizeRanges];
[self _insertElementsIntoMap:map kind:ASDataControllerRowNodeKind forSections:sectionIndexes traitCollection:traitCollection shouldFetchSizeRanges:shouldFetchSizeRanges];
// Supplementaries
for (NSString *kind in [self supplementaryKindsInSections:sectionIndexes]) {
// Step 2: Populate new elements for all sections
[self _insertElementsIntoMap:map kind:kind forSections:sectionIndexes owningNode:owningNode traitCollection:traitCollection shouldFetchSizeRanges:shouldFetchSizeRanges];
[self _insertElementsIntoMap:map kind:kind forSections:sectionIndexes traitCollection:traitCollection shouldFetchSizeRanges:shouldFetchSizeRanges];
}
}
@ -729,10 +718,11 @@ typedef void (^ASDataControllerCompletionBlock)(NSArray<ASCollectionElement *> *
return;
}
id<ASDataControllerSource> dataSource = self.dataSource;
for (ASCellNode *node in nodes) {
ASSizeRange constrainedSize = [self constrainedSizeForElement:node.collectionElement inElementMap:_pendingMap];
[self _layoutNode:node withConstrainedSize:constrainedSize];
BOOL matchesSize = [_dataSource dataController:self presentedSizeForElement:node.collectionElement matchesSize:node.frame.size];
BOOL matchesSize = [dataSource dataController:self presentedSizeForElement:node.collectionElement matchesSize:node.frame.size];
if (! matchesSize) {
[nodesSizesChanged addObject:node];
}
@ -783,8 +773,9 @@ typedef void (^ASDataControllerCompletionBlock)(NSArray<ASCollectionElement *> *
// Can't update the trait collection right away because _visibleMap may not be up-to-date,
// i.e there might be some elements that were allocated using the old trait collection but haven't been added to _visibleMap
[self _scheduleBlockOnMainSerialQueue:^{
ASPrimitiveTraitCollection newTraitCollection = [[_environmentDelegate dataControllerEnvironment] primitiveTraitCollection];
ASPrimitiveTraitCollection newTraitCollection = [self.node primitiveTraitCollection];
for (ASCollectionElement *element in _visibleMap) {
element.traitCollection = newTraitCollection;
}

View File

@ -72,9 +72,9 @@ NS_ASSUME_NONNULL_BEGIN
*/
@property (nonatomic, strong, nullable) UICollectionViewLayoutAttributes *layoutAttributes;
@property (weak, nullable) ASCollectionElement *collectionElement;
@property (atomic, weak, nullable) ASCollectionElement *collectionElement;
@property (nonatomic, weak, nullable) ASDisplayNode *owningNode;
@property (atomic, weak, nullable) id<ASRangeManagingNode> owningNode;
@property (nonatomic, assign) BOOL shouldUseUIKitCell;

View File

@ -1,5 +1,5 @@
//
// ASTableViewTests.m
// ASTableViewTests.mm
// Texture
//
// Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
@ -61,7 +61,7 @@
- (instancetype)__initWithFrame:(CGRect)frame style:(UITableViewStyle)style
{
return [super _initWithFrame:frame style:style dataControllerClass:[ASTestDataController class] eventLog:nil];
return [super _initWithFrame:frame style:style dataControllerClass:[ASTestDataController class] owningNode:nil eventLog:nil];
}
- (ASTestDataController *)testDataController