From 244ff001524127cf84c64a8cb6af64cb2f2b470e Mon Sep 17 00:00:00 2001 From: Adlai Holler Date: Wed, 16 Nov 2016 11:03:55 +0900 Subject: [PATCH 01/13] Fix carthage? --- AsyncDisplayKit.xcodeproj/project.pbxproj | 4 ++-- AsyncDisplayKit/AsyncDisplayKit.h | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/AsyncDisplayKit.xcodeproj/project.pbxproj b/AsyncDisplayKit.xcodeproj/project.pbxproj index ec5d4d482e..9ac3062590 100644 --- a/AsyncDisplayKit.xcodeproj/project.pbxproj +++ b/AsyncDisplayKit.xcodeproj/project.pbxproj @@ -443,7 +443,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 */; }; @@ -479,7 +479,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 */; }; 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 From e8688d645a8f9b34431c9223085e16c6a1bad528 Mon Sep 17 00:00:00 2001 From: Craig Howarth Date: Wed, 16 Nov 2016 17:16:15 -0500 Subject: [PATCH 02/13] [ASCollectionView] Allow Decoration Views --- AsyncDisplayKit/Details/ASCollectionViewLayoutController.mm | 1 - 1 file changed, 1 deletion(-) 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]; } From 4a48ba8be2464982a26f90e1548e47e437e82a00 Mon Sep 17 00:00:00 2001 From: Adlai Holler Date: Thu, 17 Nov 2016 11:51:35 +0900 Subject: [PATCH 03/13] Improve our event logging greatly --- AsyncDisplayKit/ASDisplayNode.mm | 2 +- AsyncDisplayKit/Details/ASEventLog.h | 11 +++- AsyncDisplayKit/Details/ASEventLog.mm | 88 ++++++++++++++++++------- AsyncDisplayKit/Details/ASTraceEvent.h | 7 +- AsyncDisplayKit/Details/ASTraceEvent.m | 24 ++++--- AsyncDisplayKitTests/ASTableViewTests.m | 2 +- 6 files changed, 96 insertions(+), 38 deletions(-) diff --git a/AsyncDisplayKit/ASDisplayNode.mm b/AsyncDisplayKit/ASDisplayNode.mm index 29a0a5011d..22930f7d77 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(); diff --git a/AsyncDisplayKit/Details/ASEventLog.h b/AsyncDisplayKit/Details/ASEventLog.h index 95c2fb0f59..1e10193c62 100644 --- a/AsyncDisplayKit/Details/ASEventLog.h +++ b/AsyncDisplayKit/Details/ASEventLog.h @@ -15,15 +15,24 @@ #endif #ifndef ASEVENTLOG_ENABLE -#define ASEVENTLOG_ENABLE 1 +#define ASEVENTLOG_ENABLE DEBUG #endif 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/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 From 8c01fccfcadedb77abe4c3dde4d6999880665d22 Mon Sep 17 00:00:00 2001 From: Scott Goodson Date: Wed, 16 Nov 2016 21:14:15 -0800 Subject: [PATCH 04/13] [ASDisplayNode] Convert assertion to log so developer can see layout issues onscreen. In this case, the user hasn't specified enough about the layout of a node. We default to 0, 0 - but ideally the case should not occur at all. So it's important to help developers detect these cases and fix them quickly. An assertion causes developers several problems: - They can't see important information unless an exception breakpoint is manually added. - They can't see their layout onscreen and so visually understanding the problem is impossible. - They can't proceed with testing to trigger other faults in the layout and are blocked fixing one at a time. A log fixes every one of those problems: - They can set a breakpoint on the log line very easily if desired. - They can see their layout display and recognize the 0,0 node even more quickly than the log text information. - They can see if multiple logs print out, or if the log only occurs for one item in a feed, or certain types -- This helps them debug faster by knowing if the layout is always broken or certain conditions break it. Since developing with ASLayoutSpecs is an iterative process, it's crucial that we let developers have the freedom to experiment and test without hitting too many assertions. Fortunately it will be impossible to ignore these huge logs (full recursive description) and their nodes will be 0, 0 size, so they will get fixed. --- AsyncDisplayKit/ASDisplayNode.mm | 8 ++++++-- AsyncDisplayKitTests/ASDisplayNodeLayoutTests.mm | 6 ------ 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/AsyncDisplayKit/ASDisplayNode.mm b/AsyncDisplayKit/ASDisplayNode.mm index 29a0a5011d..7a1804c1b5 100644 --- a/AsyncDisplayKit/ASDisplayNode.mm +++ b/AsyncDisplayKit/ASDisplayNode.mm @@ -2517,9 +2517,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/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 From c9143fb5df027d32336930df4d0078bfa9dd1aec Mon Sep 17 00:00:00 2001 From: Hannah Trosi Date: Thu, 17 Nov 2016 15:18:55 +0900 Subject: [PATCH 05/13] tableView only --- AsyncDisplayKit/ASTableView.h | 4 ++-- AsyncDisplayKit/Private/ASTableView+Undeprecated.h | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/AsyncDisplayKit/ASTableView.h b/AsyncDisplayKit/ASTableView.h index 9213a865d7..f390a380e8 100644 --- a/AsyncDisplayKit/ASTableView.h +++ b/AsyncDisplayKit/ASTableView.h @@ -38,8 +38,8 @@ 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; +@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."); /** * Retrieves the node for the row at the given index path. 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. * From 6565b8348d8f9ff719c44580ef914d14a47aabdd Mon Sep 17 00:00:00 2001 From: Hannah Trosi Date: Thu, 17 Nov 2016 16:46:07 +0900 Subject: [PATCH 06/13] collectionView --- AsyncDisplayKit/ASCollectionView.h | 36 +++++++++---------- AsyncDisplayKit/ASCollectionView.mm | 16 +++++++-- AsyncDisplayKit/ASPagerNode.m | 1 + AsyncDisplayKit/ASTableView.h | 6 ++-- AsyncDisplayKit/ASTableView.mm | 14 ++++++++ .../Private/ASCollectionView+Undeprecated.h | 18 ++++++++++ ...ASCollectionViewFlowLayoutInspectorTests.m | 1 + 7 files changed, 69 insertions(+), 23 deletions(-) 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 f80f476c2c..cd5e3697a7 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; +{ + id _asyncDelegate; + id _asyncDataSource; +} // Using _ASDisplayLayer ensures things like -layout are properly forwarded to ASCollectionNode. + (Class)layerClass @@ -363,6 +365,11 @@ static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell"; } } +- (id)asyncDataSource +{ + return _asyncDataSource; +} + - (void)setAsyncDataSource:(id)asyncDataSource { // Note: It's common to check if the value hasn't changed and short-circuit but we aren't doing that here to handle @@ -410,6 +417,11 @@ static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell"; } } +- (id)asyncDelegate +{ + return _asyncDelegate; +} + - (void)setAsyncDelegate:(id)asyncDelegate { // Note: It's common to check if the value hasn't changed and short-circuit but we aren't doing that here to handle 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/ASTableView.h b/AsyncDisplayKit/ASTableView.h index f390a380e8..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 ASDISPLAYNODE_DEPRECATED_MSG("Use ASTableNode's .delegate property instead."); -@property (nonatomic, weak) id asyncDataSource ASDISPLAYNODE_DEPRECATED_MSG("Use ASTableNode .dataSource property instead."); - /** * 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 a3b75fb5b4..6e78d68110 100644 --- a/AsyncDisplayKit/ASTableView.mm +++ b/AsyncDisplayKit/ASTableView.mm @@ -197,6 +197,10 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell"; @end @implementation ASTableView +{ + id _asyncDelegate; + id _asyncDataSource; +} // Using _ASDisplayLayer ensures things like -layout are properly forwarded to ASTableNode. + (Class)layerClass @@ -299,6 +303,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 { // Note: It's common to check if the value hasn't changed and short-circuit but we aren't doing that here to handle @@ -338,6 +347,11 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell"; super.dataSource = (id)_proxyDataSource; } +- (id)asyncDelegate +{ + return _asyncDelegate; +} + - (void)setAsyncDelegate:(id)asyncDelegate { // Note: It's common to check if the value hasn't changed and short-circuit but we aren't doing that here to handle 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/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) From 22c629648fae04d987f253c6ba482257e1255ba9 Mon Sep 17 00:00:00 2001 From: Garrett Moon Date: Fri, 18 Nov 2016 14:42:44 -0800 Subject: [PATCH 07/13] If you override the property, you need to specify __weak (#2631) --- AsyncDisplayKit/ASCollectionView.mm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/AsyncDisplayKit/ASCollectionView.mm b/AsyncDisplayKit/ASCollectionView.mm index cd5e3697a7..cc870a9f79 100644 --- a/AsyncDisplayKit/ASCollectionView.mm +++ b/AsyncDisplayKit/ASCollectionView.mm @@ -225,8 +225,8 @@ static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell"; @implementation ASCollectionView { - id _asyncDelegate; - id _asyncDataSource; + __weak id _asyncDelegate; + __weak id _asyncDataSource; } // Using _ASDisplayLayer ensures things like -layout are properly forwarded to ASCollectionNode. From 654b520b6dcd4b2f848fb075b612d53f866b64bd Mon Sep 17 00:00:00 2001 From: Garrett Moon Date: Fri, 18 Nov 2016 13:20:25 -0800 Subject: [PATCH 08/13] If you override the property, you need to specify __weak (#2630) --- AsyncDisplayKit/ASTableView.mm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/AsyncDisplayKit/ASTableView.mm b/AsyncDisplayKit/ASTableView.mm index 6e78d68110..10c4853f34 100644 --- a/AsyncDisplayKit/ASTableView.mm +++ b/AsyncDisplayKit/ASTableView.mm @@ -198,8 +198,8 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell"; @implementation ASTableView { - id _asyncDelegate; - id _asyncDataSource; + __weak id _asyncDelegate; + __weak id _asyncDataSource; } // Using _ASDisplayLayer ensures things like -layout are properly forwarded to ASTableNode. From 000dbc818e594106e61fcd40e0ca9205e6db32ba Mon Sep 17 00:00:00 2001 From: Garrett Moon Date: Sat, 19 Nov 2016 15:14:03 -0800 Subject: [PATCH 09/13] [ASCollectionView] Move ASCollectionViewLayoutInspector to its own file --- AsyncDisplayKit.xcodeproj/project.pbxproj | 58 +++++++++++ .../ASCollectionViewFlowLayoutInspector.h | 70 +------------- .../ASCollectionViewFlowLayoutInspector.m | 84 ---------------- .../Details/ASCollectionViewLayoutInspector.h | 83 ++++++++++++++++ .../Details/ASCollectionViewLayoutInspector.m | 95 +++++++++++++++++++ 5 files changed, 237 insertions(+), 153 deletions(-) create mode 100644 AsyncDisplayKit/Details/ASCollectionViewLayoutInspector.h create mode 100644 AsyncDisplayKit/Details/ASCollectionViewLayoutInspector.m diff --git a/AsyncDisplayKit.xcodeproj/project.pbxproj b/AsyncDisplayKit.xcodeproj/project.pbxproj index 9ac3062590..60926d0444 100644 --- a/AsyncDisplayKit.xcodeproj/project.pbxproj +++ b/AsyncDisplayKit.xcodeproj/project.pbxproj @@ -185,6 +185,9 @@ 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 */; }; 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 */; }; @@ -992,6 +995,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 = ""; }; @@ -1493,6 +1498,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 */, @@ -1822,6 +1829,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 */, @@ -2018,12 +2026,15 @@ isa = PBXNativeTarget; buildConfigurationList = 058D09D2195D04C000B7D73C /* Build configuration list for PBXNativeTarget "AsyncDisplayKitTests" */; buildPhases = ( + A5D6EC8A55F2AA9E9EE68B07 /* 📦 Check Pods Manifest.lock */, 2E61B6A0DB0F436A9DDBE86F /* [CP] Check Pods Manifest.lock */, 058D09B8195D04C000B7D73C /* Sources */, 058D09B9195D04C000B7D73C /* Frameworks */, 058D09BA195D04C000B7D73C /* Resources */, 3B9D88CDF51B429C8409E4B6 /* [CP] Copy Pods Resources */, B130AB1AC0A1E5162E211C19 /* [CP] Embed Pods Frameworks */, + 3BFEAD5C584653624B1B9F75 /* 📦 Embed Pods Frameworks */, + 2F77738278748228F6400335 /* 📦 Copy Pods Resources */, ); buildRules = ( ); @@ -2139,6 +2150,21 @@ shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n"; showEnvVarsInLog = 0; }; + 2F77738278748228F6400335 /* 📦 Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "📦 Copy Pods Resources"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-AsyncDisplayKitTests/Pods-AsyncDisplayKitTests-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; 3B9D88CDF51B429C8409E4B6 /* [CP] Copy Pods Resources */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; @@ -2154,6 +2180,36 @@ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-AsyncDisplayKitTests/Pods-AsyncDisplayKitTests-resources.sh\"\n"; showEnvVarsInLog = 0; }; + 3BFEAD5C584653624B1B9F75 /* 📦 Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "📦 Embed Pods Frameworks"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-AsyncDisplayKitTests/Pods-AsyncDisplayKitTests-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; + A5D6EC8A55F2AA9E9EE68B07 /* 📦 Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "📦 Check Pods Manifest.lock"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n"; + showEnvVarsInLog = 0; + }; B130AB1AC0A1E5162E211C19 /* [CP] Embed Pods Frameworks */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; @@ -2296,6 +2352,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 */, @@ -2486,6 +2543,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/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/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..d55b6506ac --- /dev/null +++ b/AsyncDisplayKit/Details/ASCollectionViewLayoutInspector.m @@ -0,0 +1,95 @@ +// +// 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 +{ + 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 From b3754942f11f33f917b66ba988ea30c435d5410d Mon Sep 17 00:00:00 2001 From: Garrett Moon Date: Sat, 19 Nov 2016 15:42:38 -0800 Subject: [PATCH 10/13] Fix build for life without cocoapods --- AsyncDisplayKit.xcodeproj/project.pbxproj | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/AsyncDisplayKit.xcodeproj/project.pbxproj b/AsyncDisplayKit.xcodeproj/project.pbxproj index 60926d0444..e40e9de593 100644 --- a/AsyncDisplayKit.xcodeproj/project.pbxproj +++ b/AsyncDisplayKit.xcodeproj/project.pbxproj @@ -188,6 +188,8 @@ 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 */; }; @@ -675,6 +677,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 */, From 7d1a670b6c066e4d21b7821a7d1d3f3fb0c1e688 Mon Sep 17 00:00:00 2001 From: Garrett Moon Date: Sat, 19 Nov 2016 15:43:47 -0800 Subject: [PATCH 11/13] Do not assert when scrollableDirections is called in base class. --- AsyncDisplayKit/Details/ASCollectionViewLayoutInspector.m | 1 - 1 file changed, 1 deletion(-) diff --git a/AsyncDisplayKit/Details/ASCollectionViewLayoutInspector.m b/AsyncDisplayKit/Details/ASCollectionViewLayoutInspector.m index d55b6506ac..960619b464 100644 --- a/AsyncDisplayKit/Details/ASCollectionViewLayoutInspector.m +++ b/AsyncDisplayKit/Details/ASCollectionViewLayoutInspector.m @@ -76,7 +76,6 @@ ASSizeRange NodeConstrainedSizeForScrollDirection(ASCollectionView *collectionVi - (ASScrollDirection)scrollableDirections { - ASDisplayNodeAssert(NO, @"layoutInspector object must implement -scrollableDirections %@", self); return ASScrollDirectionNone; } From f3fa83610faa6d06f125bbd289637cef13116b4b Mon Sep 17 00:00:00 2001 From: Garrett Moon Date: Sat, 19 Nov 2016 15:53:14 -0800 Subject: [PATCH 12/13] =?UTF-8?q?Undo=20addinng=20=F0=9F=93=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- AsyncDisplayKit.xcodeproj/project.pbxproj | 48 ----------------------- 1 file changed, 48 deletions(-) diff --git a/AsyncDisplayKit.xcodeproj/project.pbxproj b/AsyncDisplayKit.xcodeproj/project.pbxproj index e40e9de593..59b18dd574 100644 --- a/AsyncDisplayKit.xcodeproj/project.pbxproj +++ b/AsyncDisplayKit.xcodeproj/project.pbxproj @@ -2030,15 +2030,12 @@ isa = PBXNativeTarget; buildConfigurationList = 058D09D2195D04C000B7D73C /* Build configuration list for PBXNativeTarget "AsyncDisplayKitTests" */; buildPhases = ( - A5D6EC8A55F2AA9E9EE68B07 /* 📦 Check Pods Manifest.lock */, 2E61B6A0DB0F436A9DDBE86F /* [CP] Check Pods Manifest.lock */, 058D09B8195D04C000B7D73C /* Sources */, 058D09B9195D04C000B7D73C /* Frameworks */, 058D09BA195D04C000B7D73C /* Resources */, 3B9D88CDF51B429C8409E4B6 /* [CP] Copy Pods Resources */, B130AB1AC0A1E5162E211C19 /* [CP] Embed Pods Frameworks */, - 3BFEAD5C584653624B1B9F75 /* 📦 Embed Pods Frameworks */, - 2F77738278748228F6400335 /* 📦 Copy Pods Resources */, ); buildRules = ( ); @@ -2154,21 +2151,6 @@ shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n"; showEnvVarsInLog = 0; }; - 2F77738278748228F6400335 /* 📦 Copy Pods Resources */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - name = "📦 Copy Pods Resources"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-AsyncDisplayKitTests/Pods-AsyncDisplayKitTests-resources.sh\"\n"; - showEnvVarsInLog = 0; - }; 3B9D88CDF51B429C8409E4B6 /* [CP] Copy Pods Resources */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; @@ -2184,36 +2166,6 @@ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-AsyncDisplayKitTests/Pods-AsyncDisplayKitTests-resources.sh\"\n"; showEnvVarsInLog = 0; }; - 3BFEAD5C584653624B1B9F75 /* 📦 Embed Pods Frameworks */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - name = "📦 Embed Pods Frameworks"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-AsyncDisplayKitTests/Pods-AsyncDisplayKitTests-frameworks.sh\"\n"; - showEnvVarsInLog = 0; - }; - A5D6EC8A55F2AA9E9EE68B07 /* 📦 Check Pods Manifest.lock */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - name = "📦 Check Pods Manifest.lock"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n"; - showEnvVarsInLog = 0; - }; B130AB1AC0A1E5162E211C19 /* [CP] Embed Pods Frameworks */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; From 67cb789f862fa7572a06159c230612ef3ad414c4 Mon Sep 17 00:00:00 2001 From: Austin Louden Date: Mon, 21 Nov 2016 15:28:32 -0800 Subject: [PATCH 13/13] Fix self capture in ASCollectionNode (#2646) * fix capture in ASCollectionNode * fix capture self in ASTableNode --- AsyncDisplayKit/ASCollectionNode.mm | 4 +++- AsyncDisplayKit/ASTableNode.mm | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/AsyncDisplayKit/ASCollectionNode.mm b/AsyncDisplayKit/ASCollectionNode.mm index 5ecac71efc..edaaa1805e 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/ASTableNode.mm b/AsyncDisplayKit/ASTableNode.mm index 48c62cbe9c..1c7287c6a3 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]) {