diff --git a/AsyncDisplayKit.xcodeproj/project.pbxproj b/AsyncDisplayKit.xcodeproj/project.pbxproj index 4b278e9719..3adb0378fc 100644 --- a/AsyncDisplayKit.xcodeproj/project.pbxproj +++ b/AsyncDisplayKit.xcodeproj/project.pbxproj @@ -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 = ""; }; 68B8A4DF1CBDB958007E4543 /* ASWeakProxy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASWeakProxy.h; sourceTree = ""; }; 68B8A4E01CBDB958007E4543 /* ASWeakProxy.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASWeakProxy.m; sourceTree = ""; }; + 68C215561DE10D330019C4BC /* ASCollectionViewLayoutInspector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASCollectionViewLayoutInspector.h; sourceTree = ""; }; + 68C215571DE10D330019C4BC /* ASCollectionViewLayoutInspector.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASCollectionViewLayoutInspector.m; sourceTree = ""; }; 68EE0DBB1C1B4ED300BA1B99 /* ASMainSerialQueue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASMainSerialQueue.h; sourceTree = ""; }; 68EE0DBC1C1B4ED300BA1B99 /* ASMainSerialQueue.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASMainSerialQueue.mm; sourceTree = ""; }; 68FC85DC1CE29AB700EDD713 /* ASNavigationController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASNavigationController.h; sourceTree = ""; }; @@ -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 */, diff --git a/AsyncDisplayKit/ASCollectionNode.mm b/AsyncDisplayKit/ASCollectionNode.mm index 09006e9a59..fb92d555a0 100644 --- a/AsyncDisplayKit/ASCollectionNode.mm +++ b/AsyncDisplayKit/ASCollectionNode.mm @@ -121,8 +121,10 @@ - (instancetype)initWithFrame:(CGRect)frame collectionViewLayout:(UICollectionViewLayout *)layout layoutFacilitator:(id)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]) { diff --git a/AsyncDisplayKit/ASCollectionView.h b/AsyncDisplayKit/ASCollectionView.h index 88a1aaadfa..1f6fb93c8d 100644 --- a/AsyncDisplayKit/ASCollectionView.h +++ b/AsyncDisplayKit/ASCollectionView.h @@ -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 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 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 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 asyncDataSource ASDISPLAYNODE_DEPRECATED_MSG("Please use ASCollectionNode's .dataSource property instead."); + /** * Initializes an ASCollectionView * diff --git a/AsyncDisplayKit/ASCollectionView.mm b/AsyncDisplayKit/ASCollectionView.mm index 27143e6bae..8efed4eff7 100644 --- a/AsyncDisplayKit/ASCollectionView.mm +++ b/AsyncDisplayKit/ASCollectionView.mm @@ -224,8 +224,10 @@ static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell"; @end @implementation ASCollectionView -@synthesize asyncDelegate = _asyncDelegate; -@synthesize asyncDataSource = _asyncDataSource; +{ + __weak id _asyncDelegate; + __weak id _asyncDataSource; +} // Using _ASDisplayLayer ensures things like -layout are properly forwarded to ASCollectionNode. + (Class)layerClass @@ -368,6 +370,11 @@ static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell"; } } +- (id)asyncDataSource +{ + return _asyncDataSource; +} + - (void)setAsyncDataSource:(id)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)asyncDelegate +{ + return _asyncDelegate; +} + - (void)setAsyncDelegate:(id)asyncDelegate { // Changing super.delegate will trigger a setNeedsLayout, so this must happen on the main thread. diff --git a/AsyncDisplayKit/ASDisplayNode.mm b/AsyncDisplayKit/ASDisplayNode.mm index 0b97965732..862fd18dfc 100644 --- a/AsyncDisplayKit/ASDisplayNode.mm +++ b/AsyncDisplayKit/ASDisplayNode.mm @@ -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)_layoutElementThatFits:(ASSizeRange)constrainedSize diff --git a/AsyncDisplayKit/ASPagerNode.m b/AsyncDisplayKit/ASPagerNode.m index 21310e754e..4e8db5d654 100644 --- a/AsyncDisplayKit/ASPagerNode.m +++ b/AsyncDisplayKit/ASPagerNode.m @@ -16,6 +16,7 @@ #import "ASPagerFlowLayout.h" #import "ASAssert.h" #import "ASCellNode.h" +#import "ASCollectionView+Undeprecated.h" @interface ASPagerNode () { diff --git a/AsyncDisplayKit/ASTableNode.mm b/AsyncDisplayKit/ASTableNode.mm index 604f5ce8b1..9a48a4a291 100644 --- a/AsyncDisplayKit/ASTableNode.mm +++ b/AsyncDisplayKit/ASTableNode.mm @@ -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]) { diff --git a/AsyncDisplayKit/ASTableView.h b/AsyncDisplayKit/ASTableView.h index 9213a865d7..b932edc873 100644 --- a/AsyncDisplayKit/ASTableView.h +++ b/AsyncDisplayKit/ASTableView.h @@ -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 asyncDelegate; -@property (nonatomic, weak) id 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 asyncDelegate ASDISPLAYNODE_DEPRECATED_MSG("Use ASTableNode's .delegate property instead."); +@property (nonatomic, weak) id asyncDataSource ASDISPLAYNODE_DEPRECATED_MSG("Use ASTableNode .dataSource property instead."); + /** * Initializer. * diff --git a/AsyncDisplayKit/ASTableView.mm b/AsyncDisplayKit/ASTableView.mm index 51bd965fe9..ba6b303810 100644 --- a/AsyncDisplayKit/ASTableView.mm +++ b/AsyncDisplayKit/ASTableView.mm @@ -197,6 +197,10 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell"; @end @implementation ASTableView +{ + __weak id _asyncDelegate; + __weak id _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)asyncDataSource +{ + return _asyncDataSource; +} + - (void)setAsyncDataSource:(id)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)_proxyDataSource; } +- (id)asyncDelegate +{ + return _asyncDelegate; +} + - (void)setAsyncDelegate:(id)asyncDelegate { // Changing super.delegate will trigger a setNeedsLayout, so this must happen on the main thread. diff --git a/AsyncDisplayKit/AsyncDisplayKit.h b/AsyncDisplayKit/AsyncDisplayKit.h index a1691bd9fe..136016e4c3 100644 --- a/AsyncDisplayKit/AsyncDisplayKit.h +++ b/AsyncDisplayKit/AsyncDisplayKit.h @@ -92,6 +92,7 @@ #import #import #import +#import #import #import diff --git a/AsyncDisplayKit/Details/ASCollectionViewFlowLayoutInspector.h b/AsyncDisplayKit/Details/ASCollectionViewFlowLayoutInspector.h index 7453acb4b7..52df1ee1d4 100644 --- a/AsyncDisplayKit/Details/ASCollectionViewFlowLayoutInspector.h +++ b/AsyncDisplayKit/Details/ASCollectionViewFlowLayoutInspector.h @@ -10,78 +10,10 @@ #pragma once -#import -#import -#import - -@class ASCollectionView; -@protocol ASCollectionDataSource; -@protocol ASCollectionDelegate; +#include "ASCollectionViewLayoutInspector.h" NS_ASSUME_NONNULL_BEGIN -@protocol ASCollectionViewLayoutInspecting - -/** - * 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)delegate; - -/** - * Allow the inspector to respond to dataSource changes. - * - * @discussion A great time to update perform selector caches! - */ -- (void)didChangeCollectionViewDataSource:(nullable id)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 - -- (instancetype)init NS_UNAVAILABLE; -- (instancetype)initWithCollectionView:(ASCollectionView *)collectionView NS_DESIGNATED_INITIALIZER; - -@end - /** * A layout inspector implementation specific for the sizing behavior of UICollectionViewFlowLayouts */ diff --git a/AsyncDisplayKit/Details/ASCollectionViewFlowLayoutInspector.m b/AsyncDisplayKit/Details/ASCollectionViewFlowLayoutInspector.m index 7f0e1911c7..5c49d17ea2 100644 --- a/AsyncDisplayKit/Details/ASCollectionViewFlowLayoutInspector.m +++ b/AsyncDisplayKit/Details/ASCollectionViewFlowLayoutInspector.m @@ -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)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 () diff --git a/AsyncDisplayKit/Details/ASCollectionViewLayoutController.mm b/AsyncDisplayKit/Details/ASCollectionViewLayoutController.mm index 14d1a0021e..d2db393f25 100644 --- a/AsyncDisplayKit/Details/ASCollectionViewLayoutController.mm +++ b/AsyncDisplayKit/Details/ASCollectionViewLayoutController.mm @@ -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]; } diff --git a/AsyncDisplayKit/Details/ASCollectionViewLayoutInspector.h b/AsyncDisplayKit/Details/ASCollectionViewLayoutInspector.h new file mode 100644 index 0000000000..5b8c901218 --- /dev/null +++ b/AsyncDisplayKit/Details/ASCollectionViewLayoutInspector.h @@ -0,0 +1,83 @@ +// +// ASCollectionViewLayoutInspector.h +// AsyncDisplayKit +// +// Created by Garrett Moon on 11/19/16. +// Copyright © 2016 Facebook. All rights reserved. +// + +#import +#import +#import + +@class ASCollectionView; +@protocol ASCollectionDataSource; +@protocol ASCollectionDelegate; + +NS_ASSUME_NONNULL_BEGIN + +extern ASSizeRange NodeConstrainedSizeForScrollDirection(ASCollectionView *collectionView); + +@protocol ASCollectionViewLayoutInspecting + +/** + * 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)delegate; + +/** + * Allow the inspector to respond to dataSource changes. + * + * @discussion A great time to update perform selector caches! + */ +- (void)didChangeCollectionViewDataSource:(nullable id)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 + +- (instancetype)init NS_UNAVAILABLE; +- (instancetype)initWithCollectionView:(ASCollectionView *)collectionView NS_DESIGNATED_INITIALIZER; + +@end + +NS_ASSUME_NONNULL_END diff --git a/AsyncDisplayKit/Details/ASCollectionViewLayoutInspector.m b/AsyncDisplayKit/Details/ASCollectionViewLayoutInspector.m new file mode 100644 index 0000000000..960619b464 --- /dev/null +++ b/AsyncDisplayKit/Details/ASCollectionViewLayoutInspector.m @@ -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)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 diff --git a/AsyncDisplayKit/Details/ASEventLog.h b/AsyncDisplayKit/Details/ASEventLog.h index fd04166282..8db8ee1ec2 100644 --- a/AsyncDisplayKit/Details/ASEventLog.h +++ b/AsyncDisplayKit/Details/ASEventLog.h @@ -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 *)backtrace format:(NSString *)format, ... NS_FORMAT_FUNCTION(2, 3); +- (instancetype)init NS_UNAVAILABLE; + @end NS_ASSUME_NONNULL_END diff --git a/AsyncDisplayKit/Details/ASEventLog.mm b/AsyncDisplayKit/Details/ASEventLog.mm index b94ea1b494..1cd5264680 100644 --- a/AsyncDisplayKit/Details/ASEventLog.mm +++ b/AsyncDisplayKit/Details/ASEventLog.mm @@ -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 *_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 *> *)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 *)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 *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 *)eventLog +- (NSArray *)events { + NSMutableArray *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 *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 diff --git a/AsyncDisplayKit/Details/ASTraceEvent.h b/AsyncDisplayKit/Details/ASTraceEvent.h index 22267fafa2..5c77e418c7 100644 --- a/AsyncDisplayKit/Details/ASTraceEvent.h +++ b/AsyncDisplayKit/Details/ASTraceEvent.h @@ -15,10 +15,9 @@ NS_ASSUME_NONNULL_BEGIN /** * This method is dealloc safe. */ -- (instancetype)initWithObject:(id)object - backtrace:(nullable NSArray *)backtrace - format:(NSString *)format - arguments:(va_list)arguments NS_FORMAT_FUNCTION(3,0); +- (instancetype)initWithBacktrace:(nullable NSArray *)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 *backtrace; diff --git a/AsyncDisplayKit/Details/ASTraceEvent.m b/AsyncDisplayKit/Details/ASTraceEvent.m index 598cbeea21..85ff69ed0d 100644 --- a/AsyncDisplayKit/Details/ASTraceEvent.m +++ b/AsyncDisplayKit/Details/ASTraceEvent.m @@ -8,7 +8,8 @@ #import "ASTraceEvent.h" #import -#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 *)backtrace format:(NSString *)format arguments:(va_list)args +- (instancetype)initWithBacktrace:(NSArray *)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 diff --git a/AsyncDisplayKit/Private/ASCollectionView+Undeprecated.h b/AsyncDisplayKit/Private/ASCollectionView+Undeprecated.h index b633d65b68..44683e8359 100644 --- a/AsyncDisplayKit/Private/ASCollectionView+Undeprecated.h +++ b/AsyncDisplayKit/Private/ASCollectionView+Undeprecated.h @@ -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 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 asyncDataSource; + /** * Initializes an ASCollectionView * diff --git a/AsyncDisplayKit/Private/ASTableView+Undeprecated.h b/AsyncDisplayKit/Private/ASTableView+Undeprecated.h index d45a672601..3af9fd838b 100644 --- a/AsyncDisplayKit/Private/ASTableView+Undeprecated.h +++ b/AsyncDisplayKit/Private/ASTableView+Undeprecated.h @@ -19,6 +19,9 @@ NS_ASSUME_NONNULL_BEGIN */ @interface ASTableView (Undeprecated) +@property (nonatomic, weak) id asyncDelegate; +@property (nonatomic, weak) id asyncDataSource; + /** * Initializer. * diff --git a/AsyncDisplayKitTests/ASCollectionViewFlowLayoutInspectorTests.m b/AsyncDisplayKitTests/ASCollectionViewFlowLayoutInspectorTests.m index 443e1d7534..5c1091bfd6 100644 --- a/AsyncDisplayKitTests/ASCollectionViewFlowLayoutInspectorTests.m +++ b/AsyncDisplayKitTests/ASCollectionViewFlowLayoutInspectorTests.m @@ -16,6 +16,7 @@ #import "ASCollectionNode.h" #import "ASCollectionViewFlowLayoutInspector.h" #import "ASCellNode.h" +#import "ASCollectionView+Undeprecated.h" @interface ASCollectionView (Private) diff --git a/AsyncDisplayKitTests/ASDisplayNodeLayoutTests.mm b/AsyncDisplayKitTests/ASDisplayNodeLayoutTests.mm index 161b71cca8..e608989bba 100644 --- a/AsyncDisplayKitTests/ASDisplayNodeLayoutTests.mm +++ b/AsyncDisplayKitTests/ASDisplayNodeLayoutTests.mm @@ -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 diff --git a/AsyncDisplayKitTests/ASTableViewTests.m b/AsyncDisplayKitTests/ASTableViewTests.m index 0a1053b5b6..14a62bb0f5 100644 --- a/AsyncDisplayKitTests/ASTableViewTests.m +++ b/AsyncDisplayKitTests/ASTableViewTests.m @@ -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