Merge commit '67cb789f862fa7572a06159c230612ef3ad414c4'

# Conflicts:
#	AsyncDisplayKit/Details/ASEventLog.h
This commit is contained in:
Peter 2016-11-22 21:28:49 +03:00
commit c9487b2d17
24 changed files with 374 additions and 226 deletions

View File

@ -184,6 +184,11 @@
68B8A4E21CBDB958007E4543 /* ASWeakProxy.h in Headers */ = {isa = PBXBuildFile; fileRef = 68B8A4DF1CBDB958007E4543 /* ASWeakProxy.h */; };
68B8A4E31CBDB958007E4543 /* ASWeakProxy.m in Sources */ = {isa = PBXBuildFile; fileRef = 68B8A4E01CBDB958007E4543 /* ASWeakProxy.m */; };
68B8A4E41CBDB958007E4543 /* ASWeakProxy.m in Sources */ = {isa = PBXBuildFile; fileRef = 68B8A4E01CBDB958007E4543 /* ASWeakProxy.m */; };
68C215581DE10D330019C4BC /* ASCollectionViewLayoutInspector.h in Headers */ = {isa = PBXBuildFile; fileRef = 68C215561DE10D330019C4BC /* ASCollectionViewLayoutInspector.h */; settings = {ATTRIBUTES = (Public, ); }; };
68C215591DE10D330019C4BC /* ASCollectionViewLayoutInspector.m in Sources */ = {isa = PBXBuildFile; fileRef = 68C215571DE10D330019C4BC /* ASCollectionViewLayoutInspector.m */; };
68C2155A1DE10D330019C4BC /* ASCollectionViewLayoutInspector.m in Sources */ = {isa = PBXBuildFile; fileRef = 68C215571DE10D330019C4BC /* ASCollectionViewLayoutInspector.m */; };
68C2155B1DE11A790019C4BC /* ASCollectionViewLayoutInspector.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 68C215561DE10D330019C4BC /* ASCollectionViewLayoutInspector.h */; };
68C2155C1DE11AA80019C4BC /* ASObjectDescriptionHelpers.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 6907C2561DC4ECFE00374C66 /* ASObjectDescriptionHelpers.h */; };
68EE0DBE1C1B4ED300BA1B99 /* ASMainSerialQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = 68EE0DBB1C1B4ED300BA1B99 /* ASMainSerialQueue.h */; };
68EE0DBF1C1B4ED300BA1B99 /* ASMainSerialQueue.mm in Sources */ = {isa = PBXBuildFile; fileRef = 68EE0DBC1C1B4ED300BA1B99 /* ASMainSerialQueue.mm */; };
68EE0DC01C1B4ED300BA1B99 /* ASMainSerialQueue.mm in Sources */ = {isa = PBXBuildFile; fileRef = 68EE0DBC1C1B4ED300BA1B99 /* ASMainSerialQueue.mm */; };
@ -439,7 +444,7 @@
CC3B20901C3F892D00798563 /* ASBridgedPropertiesTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = CC3B208F1C3F892D00798563 /* ASBridgedPropertiesTests.mm */; };
CC4981B31D1A02BE004E13CC /* ASTableViewThrashTests.m in Sources */ = {isa = PBXBuildFile; fileRef = CC4981B21D1A02BE004E13CC /* ASTableViewThrashTests.m */; };
CC4981BD1D1C7F65004E13CC /* NSIndexSet+ASHelpers.m in Sources */ = {isa = PBXBuildFile; fileRef = CC4981BB1D1C7F65004E13CC /* NSIndexSet+ASHelpers.m */; };
CC4C2A771D88E3BF0039ACAB /* ASTraceEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = CC4C2A751D88E3BF0039ACAB /* ASTraceEvent.h */; settings = {ATTRIBUTES = (Public, ); }; };
CC4C2A771D88E3BF0039ACAB /* ASTraceEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = CC4C2A751D88E3BF0039ACAB /* ASTraceEvent.h */; };
CC4C2A781D88E3BF0039ACAB /* ASTraceEvent.m in Sources */ = {isa = PBXBuildFile; fileRef = CC4C2A761D88E3BF0039ACAB /* ASTraceEvent.m */; };
CC4C2A791D88E3BF0039ACAB /* ASTraceEvent.m in Sources */ = {isa = PBXBuildFile; fileRef = CC4C2A761D88E3BF0039ACAB /* ASTraceEvent.m */; };
CC4C2A7A1D8902350039ACAB /* ASTraceEvent.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = CC4C2A751D88E3BF0039ACAB /* ASTraceEvent.h */; };
@ -475,7 +480,7 @@
DE89C1701DCEB9CC00D49D74 /* ASLayoutElementInspectorCell.h in Headers */ = {isa = PBXBuildFile; fileRef = DE89C16A1DCEB9CC00D49D74 /* ASLayoutElementInspectorCell.h */; };
DE89C1711DCEB9CC00D49D74 /* ASLayoutElementInspectorCell.m in Sources */ = {isa = PBXBuildFile; fileRef = DE89C16B1DCEB9CC00D49D74 /* ASLayoutElementInspectorCell.m */; };
DE89C1731DCEB9CC00D49D74 /* ASLayoutElementInspectorCell.m in Sources */ = {isa = PBXBuildFile; fileRef = DE89C16B1DCEB9CC00D49D74 /* ASLayoutElementInspectorCell.m */; };
DE89C1741DCEB9CC00D49D74 /* ASLayoutElementInspectorNode.h in Headers */ = {isa = PBXBuildFile; fileRef = DE89C16C1DCEB9CC00D49D74 /* ASLayoutElementInspectorNode.h */; settings = {ATTRIBUTES = (Public, ); }; };
DE89C1741DCEB9CC00D49D74 /* ASLayoutElementInspectorNode.h in Headers */ = {isa = PBXBuildFile; fileRef = DE89C16C1DCEB9CC00D49D74 /* ASLayoutElementInspectorNode.h */; };
DE89C1751DCEB9CC00D49D74 /* ASLayoutElementInspectorNode.m in Sources */ = {isa = PBXBuildFile; fileRef = DE89C16D1DCEB9CC00D49D74 /* ASLayoutElementInspectorNode.m */; };
DE89C1771DCEB9CC00D49D74 /* ASLayoutElementInspectorNode.m in Sources */ = {isa = PBXBuildFile; fileRef = DE89C16D1DCEB9CC00D49D74 /* ASLayoutElementInspectorNode.m */; };
DE89C1781DCEB9CC00D49D74 /* ASLayoutSpec+Debug.h in Headers */ = {isa = PBXBuildFile; fileRef = DE89C16E1DCEB9CC00D49D74 /* ASLayoutSpec+Debug.h */; };
@ -667,6 +672,8 @@
dstPath = "include/$(PRODUCT_NAME)";
dstSubfolderSpec = 16;
files = (
68C2155C1DE11AA80019C4BC /* ASObjectDescriptionHelpers.h in CopyFiles */,
68C2155B1DE11A790019C4BC /* ASCollectionViewLayoutInspector.h in CopyFiles */,
DEB8ED7E1DD007F400DBDE55 /* ASLayoutElementInspectorNode.h in CopyFiles */,
69127CFE1DD2B387004BF6E2 /* ASEventLog.h in CopyFiles */,
693117CE1DC7C72700DE4784 /* ASDisplayNode+Deprecated.h in CopyFiles */,
@ -983,6 +990,8 @@
68B8A4DB1CBD911D007E4543 /* ASImageNode+AnimatedImagePrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "ASImageNode+AnimatedImagePrivate.h"; sourceTree = "<group>"; };
68B8A4DF1CBDB958007E4543 /* ASWeakProxy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASWeakProxy.h; sourceTree = "<group>"; };
68B8A4E01CBDB958007E4543 /* ASWeakProxy.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASWeakProxy.m; sourceTree = "<group>"; };
68C215561DE10D330019C4BC /* ASCollectionViewLayoutInspector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASCollectionViewLayoutInspector.h; sourceTree = "<group>"; };
68C215571DE10D330019C4BC /* ASCollectionViewLayoutInspector.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASCollectionViewLayoutInspector.m; sourceTree = "<group>"; };
68EE0DBB1C1B4ED300BA1B99 /* ASMainSerialQueue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASMainSerialQueue.h; sourceTree = "<group>"; };
68EE0DBC1C1B4ED300BA1B99 /* ASMainSerialQueue.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASMainSerialQueue.mm; sourceTree = "<group>"; };
68FC85DC1CE29AB700EDD713 /* ASNavigationController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASNavigationController.h; sourceTree = "<group>"; };
@ -1484,6 +1493,8 @@
054963481A1EA066000F8E56 /* ASBasicImageDownloader.mm */,
299DA1A71A828D2900162D41 /* ASBatchContext.h */,
299DA1A81A828D2900162D41 /* ASBatchContext.mm */,
68C215561DE10D330019C4BC /* ASCollectionViewLayoutInspector.h */,
68C215571DE10D330019C4BC /* ASCollectionViewLayoutInspector.m */,
251B8EF41BBB3D690087C538 /* ASCollectionViewFlowLayoutInspector.h */,
251B8EF51BBB3D690087C538 /* ASCollectionViewFlowLayoutInspector.m */,
205F0E1B1B373A2C007741D0 /* ASCollectionViewLayoutController.h */,
@ -1810,6 +1821,7 @@
DE89C1741DCEB9CC00D49D74 /* ASLayoutElementInspectorNode.h in Headers */,
B13CA1011C52004900E031AB /* ASCollectionNode+Beta.h in Headers */,
254C6B7E1BF94DF4003EC431 /* ASTextKitTailTruncater.h in Headers */,
68C215581DE10D330019C4BC /* ASCollectionViewLayoutInspector.h in Headers */,
B35062411B010EFD0018CF92 /* _ASAsyncTransactionGroup.h in Headers */,
B35062491B010EFD0018CF92 /* _ASCoreAnimationExtras.h in Headers */,
B350620F1B010EFD0018CF92 /* _ASDisplayLayer.h in Headers */,
@ -2285,6 +2297,7 @@
ACF6ED321B17843500DA7C62 /* ASAbsoluteLayoutSpec.mm in Sources */,
AC026B6B1BD57D6F00BBC17E /* ASChangeSetDataController.mm in Sources */,
68355B311CB5799E001D4E68 /* ASImageNode+AnimatedImage.mm in Sources */,
68C215591DE10D330019C4BC /* ASCollectionViewLayoutInspector.m in Sources */,
9CFFC6C01CCAC73C006A6476 /* ASViewController.mm in Sources */,
055F1A3519ABD3E3004DAFF1 /* ASTableView.mm in Sources */,
6959433E1D70815300B0EE1F /* ASDisplayNodeLayout.mm in Sources */,
@ -2474,6 +2487,7 @@
AC026B6C1BD57D6F00BBC17E /* ASChangeSetDataController.mm in Sources */,
34EFC7741B701D0A00AD841F /* ASAbsoluteLayoutSpec.mm in Sources */,
92074A6A1CC8BADA00918F75 /* ASControlNode+tvOS.m in Sources */,
68C2155A1DE10D330019C4BC /* ASCollectionViewLayoutInspector.m in Sources */,
DB78412E1C6BCE1600A9E2B4 /* _ASTransitionContext.m in Sources */,
B350620B1B010EFD0018CF92 /* ASTableView.mm in Sources */,
B350620E1B010EFD0018CF92 /* ASTextNode.mm in Sources */,

View File

@ -121,8 +121,10 @@
- (instancetype)initWithFrame:(CGRect)frame collectionViewLayout:(UICollectionViewLayout *)layout layoutFacilitator:(id<ASCollectionViewLayoutFacilitatorProtocol>)layoutFacilitator
{
__weak __typeof__(self) weakSelf = self;
ASDisplayNodeViewBlock collectionViewBlock = ^UIView *{
return [[ASCollectionView alloc] _initWithFrame:frame collectionViewLayout:layout layoutFacilitator:layoutFacilitator eventLog:ASDisplayNodeGetEventLog(self)];
__typeof__(self) strongSelf = weakSelf;
return [[ASCollectionView alloc] _initWithFrame:frame collectionViewLayout:layout layoutFacilitator:layoutFacilitator eventLog:ASDisplayNodeGetEventLog(strongSelf)];
};
if (self = [super initWithViewBlock:collectionViewBlock]) {

View File

@ -38,24 +38,6 @@ NS_ASSUME_NONNULL_BEGIN
*/
@interface ASCollectionView : UICollectionView
/**
* The object that acts as the asynchronous delegate of the collection view
*
* @discussion The delegate must adopt the ASCollectionDelegate protocol. The collection view maintains a weak reference to the delegate object.
*
* The delegate object is responsible for providing size constraints for nodes and indicating whether batch fetching should begin.
*/
@property (nonatomic, weak) id<ASCollectionDelegate> asyncDelegate;
/**
* The object that acts as the asynchronous data source of the collection view
*
* @discussion The datasource must adopt the ASCollectionDataSource protocol. The collection view maintains a weak reference to the datasource object.
*
* The datasource object is responsible for providing nodes or node creation blocks to the collection view.
*/
@property (nonatomic, weak) id<ASCollectionDataSource> asyncDataSource;
/**
* Returns the corresponding ASCollectionNode
*
@ -138,6 +120,24 @@ NS_ASSUME_NONNULL_BEGIN
@interface ASCollectionView (Deprecated)
/**
* The object that acts as the asynchronous delegate of the collection view
*
* @discussion The delegate must adopt the ASCollectionDelegate protocol. The collection view maintains a weak reference to the delegate object.
*
* The delegate object is responsible for providing size constraints for nodes and indicating whether batch fetching should begin.
*/
@property (nonatomic, weak) id<ASCollectionDelegate> asyncDelegate ASDISPLAYNODE_DEPRECATED_MSG("Please use ASCollectionNode's .delegate property instead.");
/**
* The object that acts as the asynchronous data source of the collection view
*
* @discussion The datasource must adopt the ASCollectionDataSource protocol. The collection view maintains a weak reference to the datasource object.
*
* The datasource object is responsible for providing nodes or node creation blocks to the collection view.
*/
@property (nonatomic, weak) id<ASCollectionDataSource> asyncDataSource ASDISPLAYNODE_DEPRECATED_MSG("Please use ASCollectionNode's .dataSource property instead.");
/**
* Initializes an ASCollectionView
*

View File

@ -224,8 +224,10 @@ static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell";
@end
@implementation ASCollectionView
@synthesize asyncDelegate = _asyncDelegate;
@synthesize asyncDataSource = _asyncDataSource;
{
__weak id<ASCollectionDelegate> _asyncDelegate;
__weak id<ASCollectionDataSource> _asyncDataSource;
}
// Using _ASDisplayLayer ensures things like -layout are properly forwarded to ASCollectionNode.
+ (Class)layerClass
@ -368,6 +370,11 @@ static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell";
}
}
- (id<ASCollectionDataSource>)asyncDataSource
{
return _asyncDataSource;
}
- (void)setAsyncDataSource:(id<ASCollectionDataSource>)asyncDataSource
{
// Changing super.dataSource will trigger a setNeedsLayout, so this must happen on the main thread.
@ -418,6 +425,11 @@ static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell";
}
}
- (id<ASCollectionDelegate>)asyncDelegate
{
return _asyncDelegate;
}
- (void)setAsyncDelegate:(id<ASCollectionDelegate>)asyncDelegate
{
// Changing super.delegate will trigger a setNeedsLayout, so this must happen on the main thread.

View File

@ -307,7 +307,7 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c)
[self _staticInitialize];
#if ASEVENTLOG_ENABLE
_eventLog = [[ASEventLog alloc] init];
_eventLog = [[ASEventLog alloc] initWithObject:self];
#endif
_contentsScaleForDisplay = ASScreenScale();
@ -2624,9 +2624,13 @@ void recursivelyTriggerDisplayForLayer(CALayer *layer, BOOL shouldBlock)
{
__ASDisplayNodeCheckForLayoutMethodOverrides;
ASDisplayNodeAssert(ASIsCGSizeValidForSize(constrainedSize), @"Cannot calculate size of node because constrained size is infinite and node does not override -calculateSizeThatFits:. Try setting style.preferredSize on the node. Node: %@", self);
#if ASDISPLAYNODE_ASSERTIONS_ENABLED
if (ASIsCGSizeValidForSize(constrainedSize) == NO) {
NSLog(@"Cannot calculate size of node: constrainedSize is infinite and node does not override -calculateSizeThatFits: or specify a preferredSize. Try setting style.preferredSize. Node: %@", [self displayNodeRecursiveDescription]);
}
#endif
return constrainedSize;
return ASIsCGSizeValidForSize(constrainedSize) ? constrainedSize : CGSizeZero;
}
- (id<ASLayoutElement>)_layoutElementThatFits:(ASSizeRange)constrainedSize

View File

@ -16,6 +16,7 @@
#import "ASPagerFlowLayout.h"
#import "ASAssert.h"
#import "ASCellNode.h"
#import "ASCollectionView+Undeprecated.h"
@interface ASPagerNode () <ASCollectionDataSource, ASCollectionDelegate, ASCollectionViewDelegateFlowLayout, ASDelegateProxyInterceptor>
{

View File

@ -79,8 +79,10 @@
- (instancetype)_initWithFrame:(CGRect)frame style:(UITableViewStyle)style dataControllerClass:(Class)dataControllerClass
{
__weak __typeof__(self) weakSelf = self;
ASDisplayNodeViewBlock tableViewBlock = ^UIView *{
return [[ASTableView alloc] _initWithFrame:frame style:style dataControllerClass:dataControllerClass eventLog:ASDisplayNodeGetEventLog(self)];
__typeof__(self) strongSelf = weakSelf;
return [[ASTableView alloc] _initWithFrame:frame style:style dataControllerClass:dataControllerClass eventLog:ASDisplayNodeGetEventLog(strongSelf)];
};
if (self = [super initWithViewBlock:tableViewBlock]) {

View File

@ -38,9 +38,6 @@ NS_ASSUME_NONNULL_BEGIN
/// The corresponding table node, or nil if one does not exist.
@property (nonatomic, weak, readonly) ASTableNode *tableNode;
@property (nonatomic, weak) id<ASTableDelegate> asyncDelegate;
@property (nonatomic, weak) id<ASTableDataSource> asyncDataSource;
/**
* Retrieves the node for the row at the given index path.
*/
@ -66,6 +63,9 @@ NS_ASSUME_NONNULL_BEGIN
@interface ASTableView (Deprecated)
@property (nonatomic, weak) id<ASTableDelegate> asyncDelegate ASDISPLAYNODE_DEPRECATED_MSG("Use ASTableNode's .delegate property instead.");
@property (nonatomic, weak) id<ASTableDataSource> asyncDataSource ASDISPLAYNODE_DEPRECATED_MSG("Use ASTableNode .dataSource property instead.");
/**
* Initializer.
*

View File

@ -197,6 +197,10 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell";
@end
@implementation ASTableView
{
__weak id<ASTableDelegate> _asyncDelegate;
__weak id<ASTableDataSource> _asyncDataSource;
}
// Using _ASDisplayLayer ensures things like -layout are properly forwarded to ASTableNode.
+ (Class)layerClass
@ -304,6 +308,11 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell";
ASDisplayNodeAssert(delegate == nil, @"ASTableView uses asyncDelegate, not UITableView's delegate property.");
}
- (id<ASTableDataSource>)asyncDataSource
{
return _asyncDataSource;
}
- (void)setAsyncDataSource:(id<ASTableDataSource>)asyncDataSource
{
// Changing super.dataSource will trigger a setNeedsLayout, so this must happen on the main thread.
@ -346,6 +355,11 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell";
super.dataSource = (id<UITableViewDataSource>)_proxyDataSource;
}
- (id<ASTableDelegate>)asyncDelegate
{
return _asyncDelegate;
}
- (void)setAsyncDelegate:(id<ASTableDelegate>)asyncDelegate
{
// Changing super.delegate will trigger a setNeedsLayout, so this must happen on the main thread.

View File

@ -92,6 +92,7 @@
#import <AsyncDisplayKit/UIView+ASConvenience.h>
#import <AsyncDisplayKit/UIImage+ASConvenience.h>
#import <AsyncDisplayKit/NSArray+Diffing.h>
#import <AsyncDisplayKit/ASObjectDescriptionHelpers.h>
#import <AsyncDisplayKit/AsyncDisplayKit+Debug.h>
#import <AsyncDisplayKit/ASDisplayNode+Deprecated.h>

View File

@ -10,78 +10,10 @@
#pragma once
#import <Foundation/Foundation.h>
#import <AsyncDisplayKit/ASDimension.h>
#import <AsyncDisplayKit/ASScrollDirection.h>
@class ASCollectionView;
@protocol ASCollectionDataSource;
@protocol ASCollectionDelegate;
#include "ASCollectionViewLayoutInspector.h"
NS_ASSUME_NONNULL_BEGIN
@protocol ASCollectionViewLayoutInspecting <NSObject>
/**
* Asks the inspector to provide a constrained size range for the given collection view node.
*/
- (ASSizeRange)collectionView:(ASCollectionView *)collectionView constrainedSizeForNodeAtIndexPath:(NSIndexPath *)indexPath;
/**
* Return the directions in which your collection view can scroll
*/
- (ASScrollDirection)scrollableDirections;
@optional
/**
* Asks the inspector to provide a constrained size range for the given supplementary node.
*/
- (ASSizeRange)collectionView:(ASCollectionView *)collectionView constrainedSizeForSupplementaryNodeOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath;
/**
* Asks the inspector for the number of supplementary views for the given kind in the specified section.
*/
- (NSUInteger)collectionView:(ASCollectionView *)collectionView supplementaryNodesOfKind:(NSString *)kind inSection:(NSUInteger)section;
/**
* Allow the inspector to respond to delegate changes.
*
* @discussion A great time to update perform selector caches!
*/
- (void)didChangeCollectionViewDelegate:(nullable id<ASCollectionDelegate>)delegate;
/**
* Allow the inspector to respond to dataSource changes.
*
* @discussion A great time to update perform selector caches!
*/
- (void)didChangeCollectionViewDataSource:(nullable id<ASCollectionDataSource>)dataSource;
#pragma mark Deprecated Methods
/**
* Asks the inspector for the number of supplementary sections in the collection view for the given kind.
*
* @deprecated This method will not be called, and it is only deprecated as a reminder to remove it.
* Supplementary elements must exist in the same sections as regular collection view items i.e. -numberOfSectionsInCollectionView:
*/
- (NSUInteger)collectionView:(ASCollectionView *)collectionView numberOfSectionsForSupplementaryNodeOfKind:(NSString *)kind ASDISPLAYNODE_DEPRECATED_MSG("Use ASCollectionNode's method instead.");
@end
/**
* A layout inspector for non-flow layouts that returns a constrained size to let the cells layout itself as
* far as possible based on the scrollable direction of the collection view. It throws exceptions for delegate
* methods that are related to supplementary node's management.
*/
@interface ASCollectionViewLayoutInspector : NSObject <ASCollectionViewLayoutInspecting>
- (instancetype)init NS_UNAVAILABLE;
- (instancetype)initWithCollectionView:(ASCollectionView *)collectionView NS_DESIGNATED_INITIALIZER;
@end
/**
* A layout inspector implementation specific for the sizing behavior of UICollectionViewFlowLayouts
*/

View File

@ -16,90 +16,6 @@
#define kDefaultItemSize CGSizeMake(50, 50)
#pragma mark - Helper Functions
// Returns a constrained size to let the cells layout itself as far as possible based on the scrollable direction
// of the collection view
static inline ASSizeRange NodeConstrainedSizeForScrollDirection(ASCollectionView *collectionView) {
CGSize maxSize = collectionView.bounds.size;
if (ASScrollDirectionContainsHorizontalDirection(collectionView.scrollableDirections)) {
maxSize.width = CGFLOAT_MAX;
} else {
maxSize.height = CGFLOAT_MAX;
}
return ASSizeRangeMake(CGSizeZero, maxSize);
}
#pragma mark - ASCollectionViewLayoutInspector
@implementation ASCollectionViewLayoutInspector {
struct {
unsigned int implementsConstrainedSizeForNodeAtIndexPathDeprecated:1;
unsigned int implementsConstrainedSizeForNodeAtIndexPath:1;
} _delegateFlags;
}
#pragma mark Lifecycle
- (instancetype)initWithCollectionView:(ASCollectionView *)collectionView
{
self = [super init];
if (self != nil) {
[self didChangeCollectionViewDelegate:collectionView.asyncDelegate];
}
return self;
}
#pragma mark ASCollectionViewLayoutInspecting
- (void)didChangeCollectionViewDelegate:(id<ASCollectionDelegate>)delegate
{
if (delegate == nil) {
memset(&_delegateFlags, 0, sizeof(_delegateFlags));
} else {
_delegateFlags.implementsConstrainedSizeForNodeAtIndexPathDeprecated = [delegate respondsToSelector:@selector(collectionView:constrainedSizeForNodeAtIndexPath:)];
_delegateFlags.implementsConstrainedSizeForNodeAtIndexPath = [delegate respondsToSelector:@selector(collectionNode:constrainedSizeForItemAtIndexPath:)];
}
}
- (ASSizeRange)collectionView:(ASCollectionView *)collectionView constrainedSizeForNodeAtIndexPath:(NSIndexPath *)indexPath
{
if (_delegateFlags.implementsConstrainedSizeForNodeAtIndexPath) {
return [collectionView.asyncDelegate collectionNode:collectionView.collectionNode constrainedSizeForItemAtIndexPath:indexPath];
} else if (_delegateFlags.implementsConstrainedSizeForNodeAtIndexPathDeprecated) {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
return [collectionView.asyncDelegate collectionView:collectionView constrainedSizeForNodeAtIndexPath:indexPath];
#pragma clang diagnostic pop
} else {
// With 2.0 `collectionView:constrainedSizeForNodeAtIndexPath:` was moved to the delegate. Assert if not implemented on the delegate but on the data source
ASDisplayNodeAssert([collectionView.asyncDataSource respondsToSelector:@selector(collectionView:constrainedSizeForNodeAtIndexPath:)] == NO, @"collectionView:constrainedSizeForNodeAtIndexPath: was moved from the ASCollectionDataSource to the ASCollectionDelegate.");
}
return NodeConstrainedSizeForScrollDirection(collectionView);
}
- (ASScrollDirection)scrollableDirections
{
ASDisplayNodeAssert(NO, @"layoutInspector object must implement -scrollableDirections %@", self);
return ASScrollDirectionNone;
}
- (ASSizeRange)collectionView:(ASCollectionView *)collectionView constrainedSizeForSupplementaryNodeOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath
{
ASDisplayNodeAssert(NO, @"To support supplementary nodes in ASCollectionView, it must have a layoutInspector for layout inspection. (See ASCollectionViewFlowLayoutInspector for an example.)");
return ASSizeRangeMake(CGSizeZero, CGSizeZero);
}
- (NSUInteger)collectionView:(ASCollectionView *)collectionView supplementaryNodesOfKind:(NSString *)kind inSection:(NSUInteger)section
{
ASDisplayNodeAssert(NO, @"To support supplementary nodes in ASCollectionView, it must have a layoutInspector for layout inspection. (See ASCollectionViewFlowLayoutInspector for an example.)");
return 0;
}
@end
#pragma mark - ASCollectionViewFlowLayoutInspector
@interface ASCollectionViewFlowLayoutInspector ()

View File

@ -60,7 +60,6 @@ typedef struct ASRangeGeometry ASRangeGeometry;
for (UICollectionViewLayoutAttributes *la in layoutAttributes) {
//ASDisplayNodeAssert(![indexPathSet containsObject:la.indexPath], @"Shouldn't already contain indexPath");
ASDisplayNodeAssert(la.representedElementCategory != UICollectionElementCategoryDecorationView, @"UICollectionView decoration views are not supported by ASCollectionView");
[indexPathSet addObject:la.indexPath];
}

View File

@ -0,0 +1,83 @@
//
// ASCollectionViewLayoutInspector.h
// AsyncDisplayKit
//
// Created by Garrett Moon on 11/19/16.
// Copyright © 2016 Facebook. All rights reserved.
//
#import <Foundation/Foundation.h>
#import <AsyncDisplayKit/ASDimension.h>
#import <AsyncDisplayKit/ASScrollDirection.h>
@class ASCollectionView;
@protocol ASCollectionDataSource;
@protocol ASCollectionDelegate;
NS_ASSUME_NONNULL_BEGIN
extern ASSizeRange NodeConstrainedSizeForScrollDirection(ASCollectionView *collectionView);
@protocol ASCollectionViewLayoutInspecting <NSObject>
/**
* Asks the inspector to provide a constrained size range for the given collection view node.
*/
- (ASSizeRange)collectionView:(ASCollectionView *)collectionView constrainedSizeForNodeAtIndexPath:(NSIndexPath *)indexPath;
/**
* Return the directions in which your collection view can scroll
*/
- (ASScrollDirection)scrollableDirections;
@optional
/**
* Asks the inspector to provide a constrained size range for the given supplementary node.
*/
- (ASSizeRange)collectionView:(ASCollectionView *)collectionView constrainedSizeForSupplementaryNodeOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath;
/**
* Asks the inspector for the number of supplementary views for the given kind in the specified section.
*/
- (NSUInteger)collectionView:(ASCollectionView *)collectionView supplementaryNodesOfKind:(NSString *)kind inSection:(NSUInteger)section;
/**
* Allow the inspector to respond to delegate changes.
*
* @discussion A great time to update perform selector caches!
*/
- (void)didChangeCollectionViewDelegate:(nullable id<ASCollectionDelegate>)delegate;
/**
* Allow the inspector to respond to dataSource changes.
*
* @discussion A great time to update perform selector caches!
*/
- (void)didChangeCollectionViewDataSource:(nullable id<ASCollectionDataSource>)dataSource;
#pragma mark Deprecated Methods
/**
* Asks the inspector for the number of supplementary sections in the collection view for the given kind.
*
* @deprecated This method will not be called, and it is only deprecated as a reminder to remove it.
* Supplementary elements must exist in the same sections as regular collection view items i.e. -numberOfSectionsInCollectionView:
*/
- (NSUInteger)collectionView:(ASCollectionView *)collectionView numberOfSectionsForSupplementaryNodeOfKind:(NSString *)kind ASDISPLAYNODE_DEPRECATED_MSG("Use ASCollectionNode's method instead.");
@end
/**
* A layout inspector for non-flow layouts that returns a constrained size to let the cells layout itself as
* far as possible based on the scrollable direction of the collection view. It throws exceptions for delegate
* methods that are related to supplementary node's management.
*/
@interface ASCollectionViewLayoutInspector : NSObject <ASCollectionViewLayoutInspecting>
- (instancetype)init NS_UNAVAILABLE;
- (instancetype)initWithCollectionView:(ASCollectionView *)collectionView NS_DESIGNATED_INITIALIZER;
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,94 @@
//
// ASCollectionViewLayoutInspector.m
// AsyncDisplayKit
//
// Created by Garrett Moon on 11/19/16.
// Copyright © 2016 Facebook. All rights reserved.
//
#import "ASCollectionViewLayoutInspector.h"
#import "ASCollectionView.h"
#import "ASCollectionView+Undeprecated.h"
#pragma mark - Helper Functions
// Returns a constrained size to let the cells layout itself as far as possible based on the scrollable direction
// of the collection view
ASSizeRange NodeConstrainedSizeForScrollDirection(ASCollectionView *collectionView) {
CGSize maxSize = collectionView.bounds.size;
if (ASScrollDirectionContainsHorizontalDirection(collectionView.scrollableDirections)) {
maxSize.width = CGFLOAT_MAX;
} else {
maxSize.height = CGFLOAT_MAX;
}
return ASSizeRangeMake(CGSizeZero, maxSize);
}
#pragma mark - ASCollectionViewLayoutInspector
@implementation ASCollectionViewLayoutInspector {
struct {
unsigned int implementsConstrainedSizeForNodeAtIndexPathDeprecated:1;
unsigned int implementsConstrainedSizeForNodeAtIndexPath:1;
} _delegateFlags;
}
#pragma mark Lifecycle
- (instancetype)initWithCollectionView:(ASCollectionView *)collectionView
{
self = [super init];
if (self != nil) {
[self didChangeCollectionViewDelegate:collectionView.asyncDelegate];
}
return self;
}
#pragma mark ASCollectionViewLayoutInspecting
- (void)didChangeCollectionViewDelegate:(id<ASCollectionDelegate>)delegate
{
if (delegate == nil) {
memset(&_delegateFlags, 0, sizeof(_delegateFlags));
} else {
_delegateFlags.implementsConstrainedSizeForNodeAtIndexPathDeprecated = [delegate respondsToSelector:@selector(collectionView:constrainedSizeForNodeAtIndexPath:)];
_delegateFlags.implementsConstrainedSizeForNodeAtIndexPath = [delegate respondsToSelector:@selector(collectionNode:constrainedSizeForItemAtIndexPath:)];
}
}
- (ASSizeRange)collectionView:(ASCollectionView *)collectionView constrainedSizeForNodeAtIndexPath:(NSIndexPath *)indexPath
{
if (_delegateFlags.implementsConstrainedSizeForNodeAtIndexPath) {
return [collectionView.asyncDelegate collectionNode:collectionView.collectionNode constrainedSizeForItemAtIndexPath:indexPath];
} else if (_delegateFlags.implementsConstrainedSizeForNodeAtIndexPathDeprecated) {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
return [collectionView.asyncDelegate collectionView:collectionView constrainedSizeForNodeAtIndexPath:indexPath];
#pragma clang diagnostic pop
} else {
// With 2.0 `collectionView:constrainedSizeForNodeAtIndexPath:` was moved to the delegate. Assert if not implemented on the delegate but on the data source
ASDisplayNodeAssert([collectionView.asyncDataSource respondsToSelector:@selector(collectionView:constrainedSizeForNodeAtIndexPath:)] == NO, @"collectionView:constrainedSizeForNodeAtIndexPath: was moved from the ASCollectionDataSource to the ASCollectionDelegate.");
}
return NodeConstrainedSizeForScrollDirection(collectionView);
}
- (ASScrollDirection)scrollableDirections
{
return ASScrollDirectionNone;
}
- (ASSizeRange)collectionView:(ASCollectionView *)collectionView constrainedSizeForSupplementaryNodeOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath
{
ASDisplayNodeAssert(NO, @"To support supplementary nodes in ASCollectionView, it must have a layoutInspector for layout inspection. (See ASCollectionViewFlowLayoutInspector for an example.)");
return ASSizeRangeMake(CGSizeZero, CGSizeZero);
}
- (NSUInteger)collectionView:(ASCollectionView *)collectionView supplementaryNodesOfKind:(NSString *)kind inSection:(NSUInteger)section
{
ASDisplayNodeAssert(NO, @"To support supplementary nodes in ASCollectionView, it must have a layoutInspector for layout inspection. (See ASCollectionViewFlowLayoutInspector for an example.)");
return 0;
}
@end

View File

@ -22,8 +22,17 @@ NS_ASSUME_NONNULL_BEGIN
@interface ASEventLog : NSObject
/**
* Create a new event log.
*
* @param anObject The object whose events we are logging. This object is not retained.
*/
- (instancetype)initWithObject:(id)anObject;
- (void)logEventWithBacktrace:(nullable NSArray<NSString *> *)backtrace format:(NSString *)format, ... NS_FORMAT_FUNCTION(2, 3);
- (instancetype)init NS_UNAVAILABLE;
@end
NS_ASSUME_NONNULL_END

View File

@ -13,57 +13,86 @@
#import "ASEventLog.h"
#import "ASThread.h"
#import "ASTraceEvent.h"
#import "ASObjectDescriptionHelpers.h"
@interface ASEventLog ()
{
@implementation ASEventLog {
ASDN::RecursiveMutex __instanceLock__;
// The index of the most recent log entry. -1 until first entry.
NSInteger _eventLogHead;
// The most recent trace events. Max count is ASEVENTLOG_CAPACITY.
NSMutableArray<ASTraceEvent *> *_eventLog;
// A description of the object we're logging for. This is immutable.
NSString *_objectDescription;
}
@end
@implementation ASEventLog
/**
* Even just when debugging, all these events can take up considerable memory.
* Store them in a shared NSCache to limit the total consumption.
*/
+ (NSCache<ASEventLog *, NSMutableArray<ASTraceEvent *> *> *)contentsCache
{
static NSCache *cache;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
cache = [[NSCache alloc] init];
});
return cache;
}
- (instancetype)init
- (instancetype)initWithObject:(id)anObject
{
if ((self = [super init])) {
_objectDescription = ASObjectDescriptionMakeTiny(anObject);
_eventLogHead = -1;
}
return self;
}
- (instancetype)init
{
// This method is marked unavailable so the compiler won't let them call it.
ASDisplayNodeFailAssert(@"Failed to call initWithObject:");
return nil;
}
- (void)logEventWithBacktrace:(NSArray<NSString *> *)backtrace format:(NSString *)format, ...
{
va_list args;
va_start(args, format);
ASTraceEvent *event = [[ASTraceEvent alloc] initWithObject:self
backtrace:backtrace
format:format
arguments:args];
ASTraceEvent *event = [[ASTraceEvent alloc] initWithBacktrace:backtrace
format:format
arguments:args];
va_end(args);
ASDN::MutexLocker l(__instanceLock__);
// Create the array if needed.
if (_eventLog == nil) {
_eventLog = [NSMutableArray arrayWithCapacity:ASEVENTLOG_CAPACITY];
NSCache *cache = [ASEventLog contentsCache];
NSMutableArray<ASTraceEvent *> *events = [cache objectForKey:self];
if (events == nil) {
events = [NSMutableArray arrayWithObject:event];
[cache setObject:events forKey:self];
_eventLogHead = 0;
return;
}
// Increment the head index.
_eventLogHead = (_eventLogHead + 1) % ASEVENTLOG_CAPACITY;
if (_eventLogHead < _eventLog.count) {
[_eventLog replaceObjectAtIndex:_eventLogHead withObject:event];
if (_eventLogHead < events.count) {
[events replaceObjectAtIndex:_eventLogHead withObject:event];
} else {
[_eventLog insertObject:event atIndex:_eventLogHead];
[events insertObject:event atIndex:_eventLogHead];
}
}
- (NSArray<ASTraceEvent *> *)eventLog
- (NSArray<ASTraceEvent *> *)events
{
NSMutableArray<ASTraceEvent *> *events = [[ASEventLog contentsCache] objectForKey:self];
if (events == nil) {
return nil;
}
ASDN::MutexLocker l(__instanceLock__);
NSUInteger tail = (_eventLogHead + 1);
NSUInteger count = _eventLog.count;
NSUInteger count = events.count;
NSMutableArray<ASTraceEvent *> *result = [NSMutableArray array];
@ -71,10 +100,25 @@
for (NSUInteger actualIndex = 0; actualIndex < ASEVENTLOG_CAPACITY; actualIndex++) {
NSInteger ringIndex = (tail + actualIndex) % ASEVENTLOG_CAPACITY;
if (ringIndex < count) {
[result addObject:_eventLog[ringIndex]];
[result addObject:events[ringIndex]];
}
}
return result;
}
- (NSString *)description
{
/**
* This description intentionally doesn't follow the standard description format.
* Since this is a log, it's important for the description to look a certain way, and
* the formal description style doesn't allow for newlines and has a ton of punctuation.
*/
NSArray *events = [self events];
if (events == nil) {
return [NSString stringWithFormat:@"Event log for %@ was purged to conserve memory.", _objectDescription];
} else {
return [NSString stringWithFormat:@"Event log for %@. Events: %@", _objectDescription, events];
}
}
@end

View File

@ -15,10 +15,9 @@ NS_ASSUME_NONNULL_BEGIN
/**
* This method is dealloc safe.
*/
- (instancetype)initWithObject:(id)object
backtrace:(nullable NSArray<NSString *> *)backtrace
format:(NSString *)format
arguments:(va_list)arguments NS_FORMAT_FUNCTION(3,0);
- (instancetype)initWithBacktrace:(nullable NSArray<NSString *> *)backtrace
format:(NSString *)format
arguments:(va_list)arguments NS_FORMAT_FUNCTION(2,0);
// Will be nil unless AS_SAVE_EVENT_BACKTRACES=1 (default=0)
@property (nonatomic, nullable, readonly) NSArray<NSString *> *backtrace;

View File

@ -8,7 +8,8 @@
#import "ASTraceEvent.h"
#import <QuartzCore/QuartzCore.h>
#import "ASObjectDescriptionHelpers.h"
static NSString *const ASTraceEventThreadDescriptionKey = @"ASThreadTraceEventDescription";
@interface ASTraceEvent ()
@property (nonatomic, strong, readonly) NSString *objectDescription;
@ -17,7 +18,7 @@
@implementation ASTraceEvent
- (instancetype)initWithObject:(id)object backtrace:(NSArray<NSString *> *)backtrace format:(NSString *)format arguments:(va_list)args
- (instancetype)initWithBacktrace:(NSArray<NSString *> *)backtrace format:(NSString *)format arguments:(va_list)args
{
self = [super init];
if (self != nil) {
@ -29,8 +30,6 @@
// Create the format string passed to us.
_message = [[NSString alloc] initWithFormat:format arguments:args];
_objectDescription = ASObjectDescriptionMakeTiny(object);
NSThread *thread = [NSThread currentThread];
NSString *threadDescription = thread.name;
@ -38,10 +37,17 @@
if ([thread isMainThread]) {
threadDescription = @"Main";
} else {
// Want these to be 4-chars to line up with "Main". It's possible that a collision could happen
// here but it's so unbelievably likely to impact development, the risk is acceptable.
NSString *ptrString = [NSString stringWithFormat:@"%p", thread];
threadDescription = [ptrString substringFromIndex:MAX(0, ptrString.length - 4)];
// If the bg thread has no name, we cache a 4-character ptr string to identify it by
// inside the thread dictionary.
NSMutableDictionary *threadDict = thread.threadDictionary;
threadDescription = threadDict[ASTraceEventThreadDescriptionKey];
if (threadDescription == nil) {
// Want these to be 4-chars to line up with "Main". It's possible that a collision could happen
// here but it's so unbelievably likely to impact development, the risk is acceptable.
NSString *ptrString = [NSString stringWithFormat:@"%p", thread];
threadDescription = [ptrString substringFromIndex:MAX(0, ptrString.length - 4)];
threadDict[ASTraceEventThreadDescriptionKey] = threadDescription;
}
}
}
_threadDescription = threadDescription;
@ -54,7 +60,7 @@
- (NSString *)description
{
return [NSString stringWithFormat:@"<%@ (%@) t=%7.3f: %@>", _objectDescription, _threadDescription, _timestamp, _message];
return [NSString stringWithFormat:@"<(%@) t=%7.3f: %@>", _threadDescription, _timestamp, _message];
}
@end

View File

@ -19,6 +19,24 @@ NS_ASSUME_NONNULL_BEGIN
*/
@interface ASCollectionView (Undeprecated)
/**
* The object that acts as the asynchronous delegate of the collection view
*
* @discussion The delegate must adopt the ASCollectionDelegate protocol. The collection view maintains a weak reference to the delegate object.
*
* The delegate object is responsible for providing size constraints for nodes and indicating whether batch fetching should begin.
*/
@property (nonatomic, weak) id<ASCollectionDelegate> asyncDelegate;
/**
* The object that acts as the asynchronous data source of the collection view
*
* @discussion The datasource must adopt the ASCollectionDataSource protocol. The collection view maintains a weak reference to the datasource object.
*
* The datasource object is responsible for providing nodes or node creation blocks to the collection view.
*/
@property (nonatomic, weak) id<ASCollectionDataSource> asyncDataSource;
/**
* Initializes an ASCollectionView
*

View File

@ -19,6 +19,9 @@ NS_ASSUME_NONNULL_BEGIN
*/
@interface ASTableView (Undeprecated)
@property (nonatomic, weak) id<ASTableDelegate> asyncDelegate;
@property (nonatomic, weak) id<ASTableDataSource> asyncDataSource;
/**
* Initializer.
*

View File

@ -16,6 +16,7 @@
#import "ASCollectionNode.h"
#import "ASCollectionViewFlowLayoutInspector.h"
#import "ASCellNode.h"
#import "ASCollectionView+Undeprecated.h"
@interface ASCollectionView (Private)

View File

@ -111,12 +111,6 @@
};
XCTAssertThrows([node layoutThatFits:ASSizeRangeMake(CGSizeMake(0, FLT_MAX))]);
// This dance is necessary as we would assert in case we create an ASDimension that is not real numbers
ASDimension width = displayNode.style.width;
width.value = INFINITY;
displayNode.style.width = width;
XCTAssertThrows([node layoutThatFits:ASSizeRangeMake(CGSizeMake(0, 0), CGSizeMake(INFINITY, INFINITY))]);
}
- (void)testThatLayoutCreatedWithInvalidSizeCausesException

View File

@ -54,7 +54,7 @@
- (instancetype)__initWithFrame:(CGRect)frame style:(UITableViewStyle)style
{
return [super _initWithFrame:frame style:style dataControllerClass:[ASTestDataController class] eventLog:[[ASEventLog alloc] init]];
return [super _initWithFrame:frame style:style dataControllerClass:[ASTestDataController class] eventLog:nil];
}
- (ASTestDataController *)testDataController