From 062bcf3631de69f596d970c21aa1ce25869d02a2 Mon Sep 17 00:00:00 2001 From: Gareth Reese Date: Tue, 21 Jun 2016 07:51:58 +0100 Subject: [PATCH 01/43] [ASVideoNode] issue #1782 Placeholder images are replaced by a blank placeholder. Now checks the .URL property of the parent class as well as the .image to ensure that new placeholders aren't generated. --- AsyncDisplayKit/ASVideoNode.mm | 4 ++-- examples/Videos/Sample/ViewController.m | 28 ++++++++++++++++++++++++- 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/AsyncDisplayKit/ASVideoNode.mm b/AsyncDisplayKit/ASVideoNode.mm index 8290e9da4d..95bb35f7dd 100644 --- a/AsyncDisplayKit/ASVideoNode.mm +++ b/AsyncDisplayKit/ASVideoNode.mm @@ -151,7 +151,7 @@ static NSString * const kStatus = @"status"; self.player = [AVPlayer playerWithPlayerItem:playerItem]; } - if (self.image == nil) { + if (self.image == nil && self.URL == nil) { [self generatePlaceholderImage]; } @@ -284,7 +284,7 @@ static NSString * const kStatus = @"status"; if ([change[NSKeyValueChangeNewKey] integerValue] == AVPlayerItemStatusReadyToPlay) { self.playerState = ASVideoNodePlayerStateReadyToPlay; // If we don't yet have a placeholder image update it now that we should have data available for it - if (self.image == nil) { + if (self.image == nil && self.URL == nil) { [self generatePlaceholderImage]; } } diff --git a/examples/Videos/Sample/ViewController.m b/examples/Videos/Sample/ViewController.m index 43a0fd6755..e2a6e22b88 100644 --- a/examples/Videos/Sample/ViewController.m +++ b/examples/Videos/Sample/ViewController.m @@ -46,6 +46,9 @@ ASVideoNode *simonVideoNode = self.simonVideoNode; [_rootNode addSubnode:simonVideoNode]; + ASVideoNode *hlsVideoNode = self.hlsVideoNode; + [_rootNode addSubnode:hlsVideoNode]; + _rootNode.layoutSpecBlock = ^ASLayoutSpec *(ASDisplayNode * _Nonnull node, ASSizeRange constrainedSize) { guitarVideoNode.layoutPosition = CGPointMake(0, 0); guitarVideoNode.preferredFrameSize = CGSizeMake([UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height/3); @@ -55,8 +58,13 @@ simonVideoNode.layoutPosition = CGPointMake(0, [UIScreen mainScreen].bounds.size.height - ([UIScreen mainScreen].bounds.size.height/3)); simonVideoNode.preferredFrameSize = CGSizeMake([UIScreen mainScreen].bounds.size.width/2, [UIScreen mainScreen].bounds.size.height/3); - return [ASStaticLayoutSpec staticLayoutSpecWithChildren:@[guitarVideoNode, nicCageVideoNode, simonVideoNode]]; + + hlsVideoNode.layoutPosition = CGPointMake(0, [UIScreen mainScreen].bounds.size.height/3); + hlsVideoNode.preferredFrameSize = CGSizeMake([UIScreen mainScreen].bounds.size.width/2, [UIScreen mainScreen].bounds.size.height/3); + + return [ASStaticLayoutSpec staticLayoutSpecWithChildren:@[guitarVideoNode, nicCageVideoNode, simonVideoNode, hlsVideoNode]]; }; + [self.view addSubnode:_rootNode]; } @@ -117,6 +125,24 @@ return simonVideoNode; } +- (ASVideoNode *)hlsVideoNode; +{ + ASVideoNode *hlsVideoNode = [[ASVideoNode alloc] init]; + + hlsVideoNode.delegate = self; + hlsVideoNode.asset = [AVAsset assetWithURL:[NSURL URLWithString:@"http://devimages.apple.com/iphone/samples/bipbop/gear1/prog_index.m3u8"]]; + hlsVideoNode.gravity = AVLayerVideoGravityResize; + hlsVideoNode.backgroundColor = [UIColor lightGrayColor]; + hlsVideoNode.shouldAutorepeat = YES; + hlsVideoNode.shouldAutoplay = YES; + hlsVideoNode.muted = YES; + + // Placeholder image + hlsVideoNode.URL = [NSURL URLWithString:@"https://upload.wikimedia.org/wikipedia/en/5/52/Testcard_F.jpg"]; + + return hlsVideoNode; +} + - (ASButtonNode *)playButton; { ASButtonNode *playButtonNode = [[ASButtonNode alloc] init]; From 71d9f64535b2824d9c9c09552d14fe0782438de7 Mon Sep 17 00:00:00 2001 From: Adlai Holler Date: Thu, 23 Jun 2016 15:52:00 -0700 Subject: [PATCH 02/43] Carry over first-pass change set improvements --- AsyncDisplayKit.xcodeproj/project.pbxproj | 8 ++ AsyncDisplayKit/ASTableView.mm | 13 ++ AsyncDisplayKit/ASTableViewInternal.h | 3 + .../Details/ASChangeSetDataController.m | 20 ++- .../Details/NSIndexSet+ASHelpers.h | 23 ++++ .../Details/NSIndexSet+ASHelpers.m | 62 +++++++++ .../Private/_ASHierarchyChangeSet.h | 31 +++-- .../Private/_ASHierarchyChangeSet.m | 120 +++++++++++------- AsyncDisplayKitTests/ASTableViewThrashTests.m | 2 + .../TestResources/ASThrashTestRecordedCase | 2 +- 10 files changed, 224 insertions(+), 60 deletions(-) create mode 100644 AsyncDisplayKit/Details/NSIndexSet+ASHelpers.h create mode 100644 AsyncDisplayKit/Details/NSIndexSet+ASHelpers.m diff --git a/AsyncDisplayKit.xcodeproj/project.pbxproj b/AsyncDisplayKit.xcodeproj/project.pbxproj index 62c3baffc7..9fa6625a99 100644 --- a/AsyncDisplayKit.xcodeproj/project.pbxproj +++ b/AsyncDisplayKit.xcodeproj/project.pbxproj @@ -546,6 +546,8 @@ CC3B208E1C3F7D0A00798563 /* ASWeakSetTests.m in Sources */ = {isa = PBXBuildFile; fileRef = CC3B208D1C3F7D0A00798563 /* ASWeakSetTests.m */; }; CC3B20901C3F892D00798563 /* ASBridgedPropertiesTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = CC3B208F1C3F892D00798563 /* ASBridgedPropertiesTests.mm */; }; CC4981B31D1A02BE004E13CC /* ASTableViewThrashTests.m in Sources */ = {isa = PBXBuildFile; fileRef = CC4981B21D1A02BE004E13CC /* ASTableViewThrashTests.m */; }; + CC4981BC1D1C7F65004E13CC /* NSIndexSet+ASHelpers.h in Headers */ = {isa = PBXBuildFile; fileRef = CC4981BA1D1C7F65004E13CC /* NSIndexSet+ASHelpers.h */; }; + CC4981BD1D1C7F65004E13CC /* NSIndexSet+ASHelpers.m in Sources */ = {isa = PBXBuildFile; fileRef = CC4981BB1D1C7F65004E13CC /* NSIndexSet+ASHelpers.m */; }; CC7FD9DE1BB5E962005CCB2B /* ASPhotosFrameworkImageRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = CC7FD9DC1BB5E962005CCB2B /* ASPhotosFrameworkImageRequest.h */; settings = {ATTRIBUTES = (Public, ); }; }; CC7FD9DF1BB5E962005CCB2B /* ASPhotosFrameworkImageRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = CC7FD9DD1BB5E962005CCB2B /* ASPhotosFrameworkImageRequest.m */; }; CC7FD9E11BB5F750005CCB2B /* ASPhotosFrameworkImageRequestTests.m in Sources */ = {isa = PBXBuildFile; fileRef = CC7FD9E01BB5F750005CCB2B /* ASPhotosFrameworkImageRequestTests.m */; }; @@ -937,6 +939,8 @@ CC3B208D1C3F7D0A00798563 /* ASWeakSetTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASWeakSetTests.m; sourceTree = ""; }; CC3B208F1C3F892D00798563 /* ASBridgedPropertiesTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASBridgedPropertiesTests.mm; sourceTree = ""; }; CC4981B21D1A02BE004E13CC /* ASTableViewThrashTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASTableViewThrashTests.m; sourceTree = ""; }; + CC4981BA1D1C7F65004E13CC /* NSIndexSet+ASHelpers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSIndexSet+ASHelpers.h"; sourceTree = ""; }; + CC4981BB1D1C7F65004E13CC /* NSIndexSet+ASHelpers.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSIndexSet+ASHelpers.m"; sourceTree = ""; }; CC7FD9DC1BB5E962005CCB2B /* ASPhotosFrameworkImageRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASPhotosFrameworkImageRequest.h; sourceTree = ""; }; CC7FD9DD1BB5E962005CCB2B /* ASPhotosFrameworkImageRequest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASPhotosFrameworkImageRequest.m; sourceTree = ""; }; CC7FD9E01BB5F750005CCB2B /* ASPhotosFrameworkImageRequestTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASPhotosFrameworkImageRequestTests.m; sourceTree = ""; }; @@ -1229,6 +1233,8 @@ 058D09E1195D050800B7D73C /* Details */ = { isa = PBXGroup; children = ( + CC4981BA1D1C7F65004E13CC /* NSIndexSet+ASHelpers.h */, + CC4981BB1D1C7F65004E13CC /* NSIndexSet+ASHelpers.m */, 9CFFC6BD1CCAC52B006A6476 /* ASEnvironment.mm */, 058D09E2195D050800B7D73C /* _ASDisplayLayer.h */, 058D09E3195D050800B7D73C /* _ASDisplayLayer.mm */, @@ -1634,6 +1640,7 @@ ACF6ED2D1B17843500DA7C62 /* ASRatioLayoutSpec.h in Headers */, AC47D9451B3BB41900AAEE9D /* ASRelativeSize.h in Headers */, 291B63FB1AA53A7A000A71B3 /* ASScrollDirection.h in Headers */, + CC4981BC1D1C7F65004E13CC /* NSIndexSet+ASHelpers.h in Headers */, D785F6621A74327E00291744 /* ASScrollNode.h in Headers */, 058D0A7F195D05F900B7D73C /* ASSentinel.h in Headers */, 9C8221951BA237B80037F19A /* ASStackBaselinePositionedLayout.h in Headers */, @@ -2101,6 +2108,7 @@ ACF6ED4C1B17847A00DA7C62 /* ASInternalHelpers.mm in Sources */, 68FC85DF1CE29AB700EDD713 /* ASNavigationController.m in Sources */, ACF6ED251B17843500DA7C62 /* ASLayout.mm in Sources */, + CC4981BD1D1C7F65004E13CC /* NSIndexSet+ASHelpers.m in Sources */, DB55C2631C6408D6004EDCF5 /* _ASTransitionContext.m in Sources */, 92074A631CC8BA1900918F75 /* ASImageNode+tvOS.m in Sources */, 251B8EFA1BBB3D690087C538 /* ASCollectionViewFlowLayoutInspector.m in Sources */, diff --git a/AsyncDisplayKit/ASTableView.mm b/AsyncDisplayKit/ASTableView.mm index c978bb9e5e..13e77c1a52 100644 --- a/AsyncDisplayKit/ASTableView.mm +++ b/AsyncDisplayKit/ASTableView.mm @@ -145,6 +145,7 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell"; // Always set, whether ASCollectionView is created directly or via ASCollectionNode. @property (nonatomic, weak) ASTableNode *tableNode; +@property (nonatomic) BOOL test_enableSuperUpdateCallLogging; @end @implementation ASTableView @@ -974,6 +975,9 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell"; BOOL preventAnimation = animationOptions == UITableViewRowAnimationNone; ASPerformBlockWithoutAnimation(preventAnimation, ^{ + if (self.test_enableSuperUpdateCallLogging) { + NSLog(@"-[super insertRowsAtIndexPaths]: %@", indexPaths); + } [super insertRowsAtIndexPaths:indexPaths withRowAnimation:(UITableViewRowAnimation)animationOptions]; [self _scheduleCheckForBatchFetchingForNumberOfChanges:indexPaths.count]; }); @@ -994,6 +998,9 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell"; BOOL preventAnimation = animationOptions == UITableViewRowAnimationNone; ASPerformBlockWithoutAnimation(preventAnimation, ^{ + if (self.test_enableSuperUpdateCallLogging) { + NSLog(@"-[super deleteRowsAtIndexPaths]: %@", indexPaths); + } [super deleteRowsAtIndexPaths:indexPaths withRowAnimation:(UITableViewRowAnimation)animationOptions]; [self _scheduleCheckForBatchFetchingForNumberOfChanges:indexPaths.count]; }); @@ -1015,6 +1022,9 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell"; BOOL preventAnimation = animationOptions == UITableViewRowAnimationNone; ASPerformBlockWithoutAnimation(preventAnimation, ^{ + if (self.test_enableSuperUpdateCallLogging) { + NSLog(@"-[super insertSections]: %@", indexSet); + } [super insertSections:indexSet withRowAnimation:(UITableViewRowAnimation)animationOptions]; [self _scheduleCheckForBatchFetchingForNumberOfChanges:indexSet.count]; }); @@ -1031,6 +1041,9 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell"; BOOL preventAnimation = animationOptions == UITableViewRowAnimationNone; ASPerformBlockWithoutAnimation(preventAnimation, ^{ + if (self.test_enableSuperUpdateCallLogging) { + NSLog(@"-[super deleteSections]: %@", indexSet); + } [super deleteSections:indexSet withRowAnimation:(UITableViewRowAnimation)animationOptions]; [self _scheduleCheckForBatchFetchingForNumberOfChanges:indexSet.count]; }); diff --git a/AsyncDisplayKit/ASTableViewInternal.h b/AsyncDisplayKit/ASTableViewInternal.h index 93cdca0fcb..22ac11ff7e 100644 --- a/AsyncDisplayKit/ASTableViewInternal.h +++ b/AsyncDisplayKit/ASTableViewInternal.h @@ -34,4 +34,7 @@ */ - (instancetype)_initWithFrame:(CGRect)frame style:(UITableViewStyle)style dataControllerClass:(Class)dataControllerClass ownedByNode:(BOOL)ownedByNode; +/// Set YES and we'll log every time we call [super insertRows…] etc +@property (nonatomic) BOOL test_enableSuperUpdateCallLogging; + @end diff --git a/AsyncDisplayKit/Details/ASChangeSetDataController.m b/AsyncDisplayKit/Details/ASChangeSetDataController.m index efce00ad31..57fb476c79 100644 --- a/AsyncDisplayKit/Details/ASChangeSetDataController.m +++ b/AsyncDisplayKit/Details/ASChangeSetDataController.m @@ -14,6 +14,7 @@ #import "ASInternalHelpers.h" #import "_ASHierarchyChangeSet.h" #import "ASAssert.h" +#import "NSIndexSet+ASHelpers.h" #import "ASDataController+Subclasses.h" @@ -47,10 +48,18 @@ [super beginUpdates]; + for (_ASHierarchyItemChange *change in [_changeSet itemChangesOfType:_ASHierarchyChangeTypeReload]) { + [super deleteRowsAtIndexPaths:change.indexPaths withAnimationOptions:change.animationOptions]; + } + for (_ASHierarchyItemChange *change in [_changeSet itemChangesOfType:_ASHierarchyChangeTypeDelete]) { [super deleteRowsAtIndexPaths:change.indexPaths withAnimationOptions:change.animationOptions]; } + for (_ASHierarchySectionChange *change in [_changeSet sectionChangesOfType:_ASHierarchyChangeTypeReload]) { + [super deleteSections:change.indexSet withAnimationOptions:change.animationOptions]; + } + for (_ASHierarchySectionChange *change in [_changeSet sectionChangesOfType:_ASHierarchyChangeTypeDelete]) { [super deleteSections:change.indexSet withAnimationOptions:change.animationOptions]; } @@ -58,13 +67,12 @@ // TODO: Shouldn't reloads be processed before deletes, since deletes affect // the index space and reloads don't? for (_ASHierarchySectionChange *change in [_changeSet sectionChangesOfType:_ASHierarchyChangeTypeReload]) { - [super reloadSections:change.indexSet withAnimationOptions:change.animationOptions]; + NSIndexSet *newIndexes = [change.indexSet as_indexesByMapping:^(NSUInteger idx) { + return [_changeSet newSectionForOldSection:idx]; + }]; + [super insertSections:newIndexes withAnimationOptions:change.animationOptions]; } - - for (_ASHierarchyItemChange *change in [_changeSet itemChangesOfType:_ASHierarchyChangeTypeReload]) { - [super reloadRowsAtIndexPaths:change.indexPaths withAnimationOptions:change.animationOptions]; - } - + for (_ASHierarchySectionChange *change in [_changeSet sectionChangesOfType:_ASHierarchyChangeTypeInsert]) { [super insertSections:change.indexSet withAnimationOptions:change.animationOptions]; } diff --git a/AsyncDisplayKit/Details/NSIndexSet+ASHelpers.h b/AsyncDisplayKit/Details/NSIndexSet+ASHelpers.h new file mode 100644 index 0000000000..fc8fc6cafe --- /dev/null +++ b/AsyncDisplayKit/Details/NSIndexSet+ASHelpers.h @@ -0,0 +1,23 @@ +// +// NSIndexSet+ASHelpers.h +// AsyncDisplayKit +// +// Created by Adlai Holler on 6/23/16. +// Copyright © 2016 Facebook. All rights reserved. +// + +#import + +@interface NSIndexSet (ASHelpers) + +- (NSIndexSet *)as_indexesByMapping:(NSUInteger (^)(NSUInteger))block; + +- (NSIndexSet *)as_intersectionWithIndexes:(NSIndexSet *)indexes; + +/// Returns all the item indexes from the given index paths that are in the given section. ++ (NSIndexSet *)as_indexSetFromIndexPaths:(NSArray *)indexPaths inSection:(NSUInteger)section; + +/// If you've got an old index, and you insert items using this index set, this returns the new index. +- (NSUInteger)as_indexByInsertingItemsBelowIndex:(NSUInteger)index; + +@end diff --git a/AsyncDisplayKit/Details/NSIndexSet+ASHelpers.m b/AsyncDisplayKit/Details/NSIndexSet+ASHelpers.m new file mode 100644 index 0000000000..183ae959e4 --- /dev/null +++ b/AsyncDisplayKit/Details/NSIndexSet+ASHelpers.m @@ -0,0 +1,62 @@ +// +// NSIndexSet+ASHelpers.m +// AsyncDisplayKit +// +// Created by Adlai Holler on 6/23/16. +// Copyright © 2016 Facebook. All rights reserved. +// + +@import UIKit; + +#import "NSIndexSet+ASHelpers.h" + +@implementation NSIndexSet (ASHelpers) + +- (NSIndexSet *)as_indexesByMapping:(NSUInteger (^)(NSUInteger))block +{ + NSMutableIndexSet *result = [NSMutableIndexSet indexSet]; + [self enumerateIndexesUsingBlock:^(NSUInteger idx, __unused BOOL * _Nonnull stop) { + NSUInteger newIndex = block(idx); + if (newIndex != NSNotFound) { + [result addIndex:newIndex]; + } + }]; + return result; +} + +- (NSIndexSet *)as_intersectionWithIndexes:(NSIndexSet *)indexes +{ + NSMutableIndexSet *result = [NSMutableIndexSet indexSet]; + [self enumerateRangesUsingBlock:^(NSRange range, BOOL * _Nonnull stop) { + [indexes enumerateRangesInRange:range options:kNilOptions usingBlock:^(NSRange range, BOOL * _Nonnull stop) { + [result addIndexesInRange:range]; + }]; + }]; + return result; +} + ++ (NSIndexSet *)as_indexSetFromIndexPaths:(NSArray *)indexPaths inSection:(NSUInteger)section +{ + NSMutableIndexSet *result = [NSMutableIndexSet indexSet]; + for (NSIndexPath *indexPath in indexPaths) { + if (indexPath.section == section) { + [result addIndex:indexPath.item]; + } + } + return result; +} + +- (NSUInteger)as_indexByInsertingItemsBelowIndex:(NSUInteger)index +{ + __block NSUInteger newIndex = index; + [self enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL * _Nonnull stop) { + if (idx <= newIndex) { + newIndex += 1; + } else { + *stop = YES; + } + }]; + return newIndex; +} + +@end diff --git a/AsyncDisplayKit/Private/_ASHierarchyChangeSet.h b/AsyncDisplayKit/Private/_ASHierarchyChangeSet.h index 6ec3b4ca75..d46d0a3622 100644 --- a/AsyncDisplayKit/Private/_ASHierarchyChangeSet.h +++ b/AsyncDisplayKit/Private/_ASHierarchyChangeSet.h @@ -13,6 +13,8 @@ #import #import +NS_ASSUME_NONNULL_BEGIN + typedef NSUInteger ASDataControllerAnimationOptions; typedef NS_ENUM(NSInteger, _ASHierarchyChangeType) { @@ -34,11 +36,11 @@ typedef NS_ENUM(NSInteger, _ASHierarchyChangeType) { @property (nonatomic, readonly) ASDataControllerAnimationOptions animationOptions; /// Index paths are sorted descending for changeType .Delete, ascending otherwise -@property (nonatomic, strong, readonly) NSArray *indexPaths; +@property (nonatomic, strong, readonly) NSArray *indexPaths; @property (nonatomic, readonly) _ASHierarchyChangeType changeType; -+ (NSDictionary *)sectionToIndexSetMapFromChanges:(NSArray *)changes ofType:(_ASHierarchyChangeType)changeType; ++ (NSDictionary *)sectionToIndexSetMapFromChanges:(NSArray<_ASHierarchyItemChange *> *)changes ofType:(_ASHierarchyChangeType)changeType; @end @interface _ASHierarchyChangeSet : NSObject @@ -56,7 +58,15 @@ typedef NS_ENUM(NSInteger, _ASHierarchyChangeType) { @precondition The change set must be completed. @returns The new section index, or NSNotFound if the given section was deleted. */ -- (NSInteger)newSectionForOldSection:(NSInteger)oldSection; +- (NSUInteger)newSectionForOldSection:(NSUInteger)oldSection; + +/** + Get the index path after the update for the item at the given index path before the update. + + @precondition The change set must be completed. + @returns The new index path, or nil if the given item (or its section) was deleted. + */ +- (nullable NSIndexPath *)newIndexPathForOldIndexPath:(NSIndexPath *)indexPath; @property (nonatomic, readonly) BOOL completed; @@ -77,13 +87,18 @@ typedef NS_ENUM(NSInteger, _ASHierarchyChangeType) { - Inserted sections, ascending order - Inserted items, ascending order */ -- (NSArray /*<_ASHierarchySectionChange *>*/ *)sectionChangesOfType:(_ASHierarchyChangeType)changeType; -- (NSArray /*<_ASHierarchyItemChange *>*/ *)itemChangesOfType:(_ASHierarchyChangeType)changeType; +- (NSArray <_ASHierarchySectionChange *> *)sectionChangesOfType:(_ASHierarchyChangeType)changeType; +- (NSArray <_ASHierarchyItemChange *> *)itemChangesOfType:(_ASHierarchyChangeType)changeType; + +/// Returns all item indexes affected by changes of the given type in the given section. +- (NSIndexSet *)indexesForItemChangesOfType:(_ASHierarchyChangeType)changeType inSection:(NSUInteger)section; - (void)deleteSections:(NSIndexSet *)sections animationOptions:(ASDataControllerAnimationOptions)options; - (void)insertSections:(NSIndexSet *)sections animationOptions:(ASDataControllerAnimationOptions)options; - (void)reloadSections:(NSIndexSet *)sections animationOptions:(ASDataControllerAnimationOptions)options; -- (void)insertItems:(NSArray *)indexPaths animationOptions:(ASDataControllerAnimationOptions)options; -- (void)deleteItems:(NSArray *)indexPaths animationOptions:(ASDataControllerAnimationOptions)options; -- (void)reloadItems:(NSArray *)indexPaths animationOptions:(ASDataControllerAnimationOptions)options; +- (void)insertItems:(NSArray *)indexPaths animationOptions:(ASDataControllerAnimationOptions)options; +- (void)deleteItems:(NSArray *)indexPaths animationOptions:(ASDataControllerAnimationOptions)options; +- (void)reloadItems:(NSArray *)indexPaths animationOptions:(ASDataControllerAnimationOptions)options; @end + +NS_ASSUME_NONNULL_END diff --git a/AsyncDisplayKit/Private/_ASHierarchyChangeSet.m b/AsyncDisplayKit/Private/_ASHierarchyChangeSet.m index c89fc99332..9b32376faf 100644 --- a/AsyncDisplayKit/Private/_ASHierarchyChangeSet.m +++ b/AsyncDisplayKit/Private/_ASHierarchyChangeSet.m @@ -12,6 +12,7 @@ #import "_ASHierarchyChangeSet.h" #import "ASInternalHelpers.h" +#import "NSIndexSet+ASHelpers.h" @interface _ASHierarchySectionChange () - (instancetype)initWithChangeType:(_ASHierarchyChangeType)changeType indexSet:(NSIndexSet *)indexSet animationOptions:(ASDataControllerAnimationOptions)animationOptions; @@ -23,7 +24,7 @@ + (void)sortAndCoalesceChanges:(NSMutableArray *)changes; /// Returns all the indexes from all the `indexSet`s of the given `_ASHierarchySectionChange` objects. -+ (NSMutableIndexSet *)allIndexesInChanges:(NSArray *)changes; ++ (NSMutableIndexSet *)allIndexesInSectionChanges:(NSArray *)changes; @end @interface _ASHierarchyItemChange () @@ -36,14 +37,29 @@ + (void)sortAndCoalesceChanges:(NSMutableArray *)changes ignoringChangesInSections:(NSIndexSet *)sections; @end +@implementation NSIndexSet (ASHierarchyHelpers) + +- (NSIndexSet *)intersectionWithIndexes:(NSIndexSet *)indexes +{ + NSMutableIndexSet *result = [NSMutableIndexSet indexSet]; + [self enumerateRangesUsingBlock:^(NSRange range, BOOL * _Nonnull stop) { + [indexes enumerateRangesInRange:range options:kNilOptions usingBlock:^(NSRange range, BOOL * _Nonnull stop) { + [result addIndexesInRange:range]; + }]; + }]; + return result; +} + +@end + @interface _ASHierarchyChangeSet () -@property (nonatomic, strong, readonly) NSMutableArray *insertItemChanges; -@property (nonatomic, strong, readonly) NSMutableArray *deleteItemChanges; -@property (nonatomic, strong, readonly) NSMutableArray *reloadItemChanges; -@property (nonatomic, strong, readonly) NSMutableArray *insertSectionChanges; -@property (nonatomic, strong, readonly) NSMutableArray *deleteSectionChanges; -@property (nonatomic, strong, readonly) NSMutableArray *reloadSectionChanges; +@property (nonatomic, strong, readonly) NSMutableArray<_ASHierarchyItemChange *> *insertItemChanges; +@property (nonatomic, strong, readonly) NSMutableArray<_ASHierarchyItemChange *> *deleteItemChanges; +@property (nonatomic, strong, readonly) NSMutableArray<_ASHierarchyItemChange *> *reloadItemChanges; +@property (nonatomic, strong, readonly) NSMutableArray<_ASHierarchySectionChange *> *insertSectionChanges; +@property (nonatomic, strong, readonly) NSMutableArray<_ASHierarchySectionChange *> *deleteSectionChanges; +@property (nonatomic, strong, readonly) NSMutableArray<_ASHierarchySectionChange *> *reloadSectionChanges; @end @@ -103,24 +119,52 @@ } } -- (NSInteger)newSectionForOldSection:(NSInteger)oldSection +- (NSIndexSet *)indexesForItemChangesOfType:(_ASHierarchyChangeType)changeType inSection:(NSUInteger)section +{ + [self _ensureCompleted]; + NSMutableIndexSet *result = [NSMutableIndexSet indexSet]; + for (_ASHierarchyItemChange *change in [self itemChangesOfType:changeType]) { + [result addIndexes:[NSIndexSet as_indexSetFromIndexPaths:change.indexPaths inSection:section]]; + } + return result; +} + +- (NSUInteger)newSectionForOldSection:(NSUInteger)oldSection { [self _ensureCompleted]; if ([_deletedSections containsIndex:oldSection]) { return NSNotFound; } - __block NSInteger newIndex = oldSection - [_deletedSections countOfIndexesInRange:NSMakeRange(0, oldSection)]; - [_insertedSections enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL * _Nonnull stop) { - if (idx <= newIndex) { - newIndex += 1; - } else { - *stop = YES; - } - }]; + NSUInteger newIndex = oldSection - [_deletedSections countOfIndexesInRange:NSMakeRange(0, oldSection)]; + newIndex = [_insertedSections as_indexByInsertingItemsBelowIndex:newIndex]; return newIndex; } +- (nullable NSIndexPath *)newIndexPathForOldIndexPath:(NSIndexPath *)indexPath +{ + [self _ensureCompleted]; + // If section was deleted, nil + NSUInteger oldSection = indexPath.section; + NSUInteger newSection = [self newSectionForOldSection:oldSection]; + if (newSection == NSNotFound) { + return nil; + } + + NSUInteger newItem = indexPath.item; + NSIndexSet *deletedItemsInOldSection = [self indexesForItemChangesOfType:_ASHierarchyChangeTypeDelete inSection:oldSection]; + newItem -= [deletedItemsInOldSection countOfIndexesInRange:NSMakeRange(0, newItem)]; + + for (_ASHierarchyItemChange *change in _deleteItemChanges) { + // If item was deleted, nil + if ([change.indexPaths containsObject:indexPath]) { + return nil; + } + } + + return [NSIndexPath indexPathForItem:newItem inSection:newSection]; +} + - (void)deleteItems:(NSArray *)indexPaths animationOptions:(ASDataControllerAnimationOptions)options { [self _ensureNotCompleted]; @@ -184,10 +228,13 @@ [_ASHierarchySectionChange sortAndCoalesceChanges:_insertSectionChanges]; [_ASHierarchySectionChange sortAndCoalesceChanges:_reloadSectionChanges]; - _deletedSections = [[_ASHierarchySectionChange allIndexesInChanges:_deleteSectionChanges] copy]; - _insertedSections = [[_ASHierarchySectionChange allIndexesInChanges:_insertSectionChanges] copy]; - _reloadedSections = [[_ASHierarchySectionChange allIndexesInChanges:_reloadSectionChanges] copy]; + _deletedSections = [[_ASHierarchySectionChange allIndexesInSectionChanges:_deleteSectionChanges] copy]; + _insertedSections = [[_ASHierarchySectionChange allIndexesInSectionChanges:_insertSectionChanges] copy]; + _reloadedSections = [[_ASHierarchySectionChange allIndexesInSectionChanges:_reloadSectionChanges] copy]; + NSIndexSet *deletedAndReloaded = [_deletedSections intersectionWithIndexes:_reloadedSections]; + NSAssert(deletedAndReloaded.count == 0, @"Request to delete and reload the same section(s): %@", deletedAndReloaded); + // These are invalid old section indexes. NSMutableIndexSet *deletedOrReloaded = [_deletedSections mutableCopy]; [deletedOrReloaded addIndexes:_reloadedSections]; @@ -223,39 +270,22 @@ // - delete/reload indexPaths that are passed in should all be their current indexPaths // - insert indexPaths that are passed in should all be their future indexPaths after deletions for (NSIndexPath *indexPath in change.indexPaths) { - __block NSUInteger section = indexPath.section; - __block NSUInteger row = indexPath.row; - - - // Update section number based on section insertions/deletions that are above the current section - section -= [_deletedSections countOfIndexesInRange:NSMakeRange(0, section)]; - [_insertedSections enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL * _Nonnull stop) { - if (idx <= section) { - section += 1; - } else { - *stop = YES; - } - }]; + NSUInteger section = [self newSectionForOldSection:indexPath.section]; + NSUInteger item = indexPath.item; // Update row number based on deletions that are above the current row in the current section NSIndexSet *indicesDeletedInSection = deletedIndexPathsMap[@(indexPath.section)]; - row -= [indicesDeletedInSection countOfIndexesInRange:NSMakeRange(0, row)]; + item -= [indicesDeletedInSection countOfIndexesInRange:NSMakeRange(0, item)]; // Update row number based on insertions that are above the current row in the future section NSIndexSet *indicesInsertedInSection = insertedIndexPathsMap[@(section)]; - [indicesInsertedInSection enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL * _Nonnull stop) { - if (idx <= row) { - row += 1; - } else { - *stop = YES; - } - }]; + item = [indicesInsertedInSection as_indexByInsertingItemsBelowIndex:item]; //TODO: reuse the old indexPath object if section and row aren't changed - NSIndexPath *newIndexPath = [NSIndexPath indexPathForRow:row inSection:section]; + NSIndexPath *newIndexPath = [NSIndexPath indexPathForItem:item inSection:section]; [newIndexPaths addObject:newIndexPath]; } - // All reload changes are coalesced into deletes and inserts + // All reload changes are translated into deletes and inserts // We delete the items that needs reload together with other deleted items, at their original index _ASHierarchyItemChange *deleteItemChangeFromReloadChange = [[_ASHierarchyItemChange alloc] initWithChangeType:_ASHierarchyChangeTypeDelete indexPaths:change.indexPaths animationOptions:change.animationOptions presorted:NO]; [_deleteItemChanges addObject:deleteItemChangeFromReloadChange]; @@ -346,7 +376,7 @@ [changes setArray:result]; } -+ (NSMutableIndexSet *)allIndexesInChanges:(NSArray *)changes ++ (NSMutableIndexSet *)allIndexesInSectionChanges:(NSArray<_ASHierarchySectionChange *> *)changes { NSMutableIndexSet *indexes = [NSMutableIndexSet indexSet]; for (_ASHierarchySectionChange *change in changes) { @@ -387,9 +417,9 @@ NSNumber *sectionKey = @(indexPath.section); NSMutableIndexSet *indexSet = sectionToIndexSetMap[sectionKey]; if (indexSet) { - [indexSet addIndex:indexPath.row]; + [indexSet addIndex:indexPath.item]; } else { - indexSet = [NSMutableIndexSet indexSetWithIndex:indexPath.row]; + indexSet = [NSMutableIndexSet indexSetWithIndex:indexPath.item]; sectionToIndexSetMap[sectionKey] = indexSet; } } diff --git a/AsyncDisplayKitTests/ASTableViewThrashTests.m b/AsyncDisplayKitTests/ASTableViewThrashTests.m index 5d6fa8f637..ffdfa7eec8 100644 --- a/AsyncDisplayKitTests/ASTableViewThrashTests.m +++ b/AsyncDisplayKitTests/ASTableViewThrashTests.m @@ -8,6 +8,7 @@ @import XCTest; #import +#import "ASTableViewInternal.h" // Set to 1 to use UITableView and see if the issue still exists. #define USE_UIKIT_REFERENCE 0 @@ -477,6 +478,7 @@ static NSInteger ASThrashUpdateCurrentSerializationVersion = 1; } ASThrashDataSource *ds = [[ASThrashDataSource alloc] initWithData:_update.oldData]; + ds.tableView.test_enableSuperUpdateCallLogging = YES; [self applyUpdate:_update toDataSource:ds]; [self verifyDataSource:ds]; } diff --git a/AsyncDisplayKitTests/TestResources/ASThrashTestRecordedCase b/AsyncDisplayKitTests/TestResources/ASThrashTestRecordedCase index 9e8343590e..e9dc1e9cc0 100644 --- a/AsyncDisplayKitTests/TestResources/ASThrashTestRecordedCase +++ b/AsyncDisplayKitTests/TestResources/ASThrashTestRecordedCase @@ -1 +1 @@ -YnBsaXN0MDDUAAEAAgADAAQABQAGDfYN91gkdmVyc2lvblgkb2JqZWN0c1kkYXJjaGl2ZXJUJHRvcBIAAYagrxEDRQAHAAgADwAtAC4ALwAwADEAMgAzADQANQA2ADcAOAA5AEAARgBdAGEAaABrAG4AcQB0AHcAegB9AIAAgwCGAIkAjACPAJIAlQCYAJsAngChAKYAqgCuAMUAyADLAM4A0QDUANcA2gDdAOAA4wDmAOkA7ADvAPIA9QD4APsA/gEBAQUBHAEfASIBJQEoASsBLgExATQBNwE6AT0BQAFDAUYBSQFMAU8BUgFVAVgBXAFzAXYBeQF8AX8BggGFAYgBiwGOAZEBlAGXAZoBnQGgAaMBpgGpAawBrwG1AbkBvgHDAdsB4AHjAeYB6AHqAewB7wHyAfQB9gH5AfwB/wICAgUCBwIKAg0CDwITAhYCGAIaAhwCIAIjAiYCKQIsAkMCSAJLAk4CUwJWAlkCXQJgAmQCZwJsAm8CcgJ4AnsCfgKBAoUCiAKNApACkwKXApoCngKhAqYCqQKsArECtAK3Ar0CwALDAsYCywLOAtEC2ALbAt4C4QLkAu4C8QL0AvcC+gL9AwADAwMHAwoDEAMTAxYDGQMeAyEDJAMnAz4DQgNZA1wDXwNiA2UDaANrA24DcQN0A3cDegN9A4ADgwOGA4kDjAOPA5IDlQOZA7ADswO2A7kDvAO/A8IDxQPIA8sDzgPRA9QD1wPaA90D4APjA+YD6QPsA/AEBwQKBA0EEAQTBBYEGQQcBB8EIgQlBCgEKwQuBDEENAQ3BDoEPQRABEMERwReBGEEZARnBGoEbQRwBHMEdgR5BHwEfwSCBIUEiASLBI4EkQSUBJcEmgSeBLUEuAS7BL4EwQTEBMcEygTNBNAE0wTWBNkE3ATfBOIE5QToBOsE7gTxBPUFDAUPBRIFFQUYBRsFHgUhBSQFJwUqBS0FMAUzBTYFOQU8BT8FQgVFBUgFTAVjBWYFaQVsBW8FcgV1BXgFewV+BYEFhAWHBYoFjQWQBZMFlgWZBZwFnwWjBboFvQXABcMFxgXJBcwFzwXSBdUF2AXbBd4F4QXkBecF6gXtBfAF8wX2BfoGEQYUBhcGGgYdBiAGIwYmBikGLAYvBjIGNQY4BjsGPgZBBkQGRwZKBk0GUQZoBmsGbgZxBnQGdwZ6Bn0GgAaDBoYGiQaMBo8GkgaVBpgGmwaeBqEGpAaoBr8GwgbFBsgGywbOBtEG1AbXBtoG3QbgBuMG5gbpBuwG7wbyBvUG+Ab7Bv8HFgcZBxwHHwciByUHKAcrBy4HMQc0BzcHOgc9B0AHQwdGB0kHTAdPB1IHVgdtB3AHcwd2B3kHfAd/B4IHhQeIB4sHjgeRB5QHlweaB50HoAejB6YHqQetB8QHxwfKB80H0AfTB9YH2QfcB98H4gflB+gH6wfuB/EH9Af3B/oH/QgACAQIGwgeCCEIJAgnCCoILQgwCDMINgg5CDwIPwhCCEUISAhLCE4IUQhUCFcIWwhyCHUIeAh7CH4IgQiECIcIigiNCJAIkwiWCJkInAifCKIIpQioCKsIrgiyCMkIzAjPCNII1QjYCNsI3gjhCOQI5wjqCO0I8AjzCPYI+Qj8CP8JAgkFCQkJIAkjCSYJKQksCS8JMgk1CTgJOwk+CUEJRAlHCUoJTQlQCVMJVglZCVwJYAl3CXoJfQmACYMJhgmJCYwJjwmSCZUJmAmbCZ4JoQmkCacJqgmtCbAJswm3Cc4J0QnUCdcJ2gndCeAJ4wnmCekJ7AnvCfIJ9Qn4CfsJ/goBCgQKBwoKCiIKJQo8Cj8KQgpcCl8KYgplCmgKfQqACpUKmAqwCrMKtgq6Cs0K0ArTCtYK2QrcCt8K4grlCugK6wruCvEK9Ar3CvoK/QsBCxcLGgsdCyALIwsmCykLLAsvCzILNQs4CzsLPgtBC0QLRwtKC00LUAtTC2wLbwtyC3ULjAuPC5ILrAuvC7ILtQu4C8wLzwvmC+kL7AvvDAgMCwwODBEMFQwoDCsMLgwxDDQMNww6DD0MQAxDDEYMSQxMDE8MUgxVDFgMWwxyDHUMeAx7DH4MgQyWDJkMnAyfDLYMuQy8DL8M1gzYDNsM3QzgDOMM5gzpDOwM7gzwDPIM9Az2DPgM+gz9DQANAw0GDQkNCw0ODRENFA0XDRoNMQ0zDTYNOQ08DT8NQg1FDUgNSw1NDU8NUQ1TDVYNWQ1cDV8NYQ1kDWcNag1tDXANcw11DXgNew1+DYENgw2bDZ8NpQ2oDaoNrQ2wDbUNug2+DcQNxw3MDdIN2Q3eDeIN5Q3oDe4N8lUkbnVsbNMACQAKAAsADAANAA5VX2RpY3RYX3ZlcnNpb25WJGNsYXNzgAIQAYEDRNMAEAARAAsAEgAf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rxAUAV4BXwFgAWEBYgFjAWQBZQFmAWcBaAFpAWoBawFsAW0BbgFvAXABcYBXgFiAWYBagFuAXIBdgF6AX4BggGGAYoBjgGSAZYBmgGeAaIBpgGqAJ9IAXgALAXQAYBEEToAT0gBeAAsBdwBgEQRPgBPSAF4ACwF6AGARBFCAE9IAXgALAX0AYBEEUYAT0gBeAAsBgABgEQRSgBPSAF4ACwGDAGARBFOAE9IAXgALAYYAYBEEVIAT0gBeAAsBiQBgEQRVgBPSAF4ACwGMAGARBFaAE9IAXgALAY8AYBEEV4AT0gBeAAsBkgBgEQRYgBPSAF4ACwGVAGARBFmAE9IAXgALAZgAYBEEWoAT0gBeAAsBmwBgEQRbgBPSAF4ACwGeAGARBFyAE9IAXgALAaEAYBEEXYAT0gBeAAsBpABgEQRegBPSAF4ACwGnAGARBF+AE9IAXgALAaoAYBEEYIAT0gBeAAsBrQBgEQRhgBPTAbAACwGxAbIBswG0XE5TUmFuZ2VDb3VudFtOU1JhbmdlRGF0YRACgG6AbNIBtgALAbcBuFdOUy5kYXRhRAYCEAGAbdIAYgBjAboBu11OU011dGFibGVEYXRhowG8Ab0AZ11OU011dGFibGVEYXRhVk5TRGF0YdIAYgBjAb8BwF8QEU5TTXV0YWJsZUluZGV4U2V0owHBAcIAZ18QEU5TTXV0YWJsZUluZGV4U2V0Wk5TSW5kZXhTZXTSABEACwHEAD+vEBUBxQHGAccByAHJAcoBywHMAc0BzgHPAdAB0QHSAdMB1AHVAdYB1wHYAdmAcIBxgHOAdIB1gHaAeIB5gHqAfIB9gH+AgICCgIOAhYCGgIeAiICKgIyAJ9QB3AALAbAB3QHeAbMADQANWk5TTG9jYXRpb25YTlNMZW5ndGgQAIBu0wGwAAsBsQGyAbMB4oBugHLSAbYACwHkAbhEAgEUAoBt0gGwAAsB3gGzgG7SAbAACwHeAbOAbtIBsAALAd4Bs4Bu0wGwAAsBsQGyAbMB7oBugHfSAbYACwHwAbhEEAETAYBt0gGwAAsB3gGzgG7SAbAACwHeAbOAbtMBsAALAbEBsgGzAfiAboB70gG2AAsB+gG4RAMBDAGAbdQB3AALAbAB3QH9AbMADQANEAeAbtMBsAALAbEBsgGzAgGAboB+0gG2AAsCAwG4RAwCFAGAbdIB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E9IAXgALBRMAYBECgoAT0gBeAAsFFgBgEQKDgBPSAF4ACwUZAGARAoSAE9IAXgALBRwAYBEChYAT0gBeAAsFHwBgEQKGgBPSAF4ACwUiAGARAoeAE9IAXgALBSUAYBECiIAT0gBeAAsFKABgEQKJgBPSAF4ACwUrAGARAoqAE9IAXgALBS4AYBECi4AT0gBeAAsFMQBgEQKMgBPSAF4ACwU0AGARAo2AE9IAXgALBTcAYBECjoAT0gBeAAsFOgBgEQKPgBPSAF4ACwU9AGARApCAE9IAXgALBUAAYBECkYAT0gBeAAsFQwBgEQKSgBPSAF4ACwVGAGARApOAE9MAQQBCAAsFSQVKAEWBAVIQW4Ao0gARAAsFTQA/rxAUBU4FTwVQBVEFUgVTBVQFVQVWBVcFWAVZBVoFWwVcBV0FXgVfBWAFYYEBU4EBVIEBVYEBVoEBV4EBWIEBWYEBWoEBW4EBXIEBXYEBXoEBX4EBYIEBYYEBYoEBY4EBZIEBZYEBZoAn0gBeAAsFZABgEQKUgBPSAF4ACwVnAGARApWAE9IAXgALBWoAYBECloAT0gBeAAsFbQBgEQKXgBPSAF4ACwVwAGARApiAE9IAXgALBXMAYBECmYAT0gBeAAsFdgBgEQKagBPSAF4ACwV5AGARApuAE9IAXgALBXwAYBECnIAT0gBeAAsFfwBgEQKdgBPSAF4ACwWCAGARAp6AE9IAXgALBYUAYBECn4AT0gBeAAsFiABgEQKggBPSAF4ACwWLAGARAqGAE9IAXgALBY4AYBECooAT0gBeAAsFkQBgEQKjgBPSAF4ACwWUAGARAqSAE9IAXgALBZcAYBECpYAT0gBeAAsFmgBgEQKmgBPSAF4ACwWdAGARAqeAE9MAQQBCAAsFoAWhAEWBAWgQXIAo0gARAAsFpAA/rxAUBaUFpgWnBagFqQWqBasFrAWtBa4FrwWwBbEFsgWzBbQFtQW2BbcFuIEBaYEBaoEBa4EBbIEBbYEBboEBb4EBcIEBcYEBcoEBc4EBdIEBdYEBdoEBd4EBeIEBeYEBeoEBe4EBfIAn0gBeAAsFuwBgEQKogBPSAF4ACwW+AGARAqmAE9IAXgALBcEAYBECqoAT0gBeAAsFxABgEQKrgBPSAF4ACwXHAGARAqyAE9IAXgALBcoAYBECrYAT0gBeAAsFzQBgEQKugBPS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ToECT4ECUIECUYDGgQJTgQJUgMeBAliAJ9IAXgALDHMAYBEEc4AT0gBeAAsMdgBgEQR0gBPSAF4ACwx5AGARBHWAE9IAXgALDHwAYBEEdoAT0wBBAEIACwx/CV4ARYEC7YAo0gARAAsMggA/rxASCWIJYwMbCWUJZglnCWgMiglqCWsMjQlsCW4JbwlxCXIJcwMcgQJbgQJcgMmBAl6BAl+BAmCBAmGBAu6BAmOBAmSBAu+BAmWBAmeBAmiBAmqBAmuBAmyAyoAn0gBeAAsMlwBgEQR3gBPSAF4ACwyaAGARBHiAE9MAQQBCAAsMnQm1AEWBAvGAKNIAEQALDKAAP68QFAm5CboJuwm8Cb0Mpgm+Cb8JwAnBCcIJwwnECcUJxgnHCcgJyQnLCcyBAnGBAnKBAnOBAnSBAnWBAvKBAnaBAneBAniBAnmBAnqBAnuBAnyBAn2BAn6BAn+BAoCBAoGBAoOBAoSAJ9IAXgALDLcAYBEEeYAT0wGwAAsBsQIQAbMMu4BugQL00gG2AAsMvQG4RgIBDQEQAoBt0gARAAsMwAA/rxAUDMEMwgzDDMQMxQzGDMcMyAzJDMoMywzMDM0MzgzPDNAM0QzSDNMM1IEC9oEC94EC+IEC+YEC+4EC/YEC/oEC/4EDAIEDAYEDAoEDA4EDBIEDBYEDB4EDCYEDCoEDC4EDDYEDD4An0gGwAAsB3gGzgG7UAdwACwGwAd0M2QGzAA0ADRANgG7SAbAACwHeAbOAbtMBsAALAbEBsgGzDN+AboEC+tIBtgALDOEBuEQDAQ0BgG3TAbAACwGxAbIBswzlgG6BAvzSAbYACwznAbhEAgEOAYBt1AHcAAsBsAHdDOoBswANAA0QDoBu0gGwAAsB3gGzgG7SAbAACwHeAbOAbtIBsAALAd4Bs4Bu0gGwAAsB3gGzgG7UAdwACwGwAd0CEAGzAA0ADYBu0gGwAAsB3gGzgG7SAbAACwHeAbOAbtMBsAALAbECEAGzDPyAboEDBtIBtgALDP4BuEYCAQoBDwGAbdMBsAALAbEBsgGzDQKAboEDCNIBtgALDQQBuEQEAQYBgG3UAdwACwGwAd0NBwGzAA0ADRATgG7SAbAACwHeAbOAbtMBsAALAbECEAGzDQ2AboEDDNIBtgALDQ8BuEYEAQYBEQKAbdMBsAALAbECHQGzDROAboEDDtIB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FUYVSBVKFUwVThVQFVkVXBVeFWcVahVsFXUVeBV6FYMVhhWIFZEVoBWiFaQVphWoFaoVrBWuFbAVuRW8Fb4VxxXKFcwV1RXYFdoV4xXmFegV8RX0FfYV/xYCFgQWDRYQFhIWGxYeFiAWIhYrFi4WMBY5FkAWQhZEFkYWSBZRFlQWVhZfFmIWZBZtFnAWchZ7FoAWghaEFoYWjxaSFpQWnRagFqIWqxasFq4WtxbiFuQW5hboFusW7hbxFvQW9xb6Fv0XABcDFwYXCRcMFw8XEhcVFxgXGxcdFyoXLBcuFzAXORdkF2YXaBdqF2wXbhdwF3IXdBd2F3gXehd8F34XgBeCF4QXhheIF4oXjBeOF5cXmhecF6UXqBeqF7MXthe4F8EXxBfGF88X0hfUF90X4BfiF+sX7hfwF/kX/Bf+GAcYChgMGBUYGBgaGCMYJhgoGDEYNBg2GD8YQhhEGE0YUBhSGFsYXhhgGGkYbBhuGHcYehh8GIUYiBiKGJMYlhiYGKEYpBimGLMYtRi3GLkYwhjtGO8Y8RjzGPUY9xj5GPsY/Rj/GQEZAxkFGQcZCRkLGQ0ZDxkRGRMZFRkXGSAZIxklGS4ZMRkzGTwZPxlBGUoZTRlPGVgZWxldGWYZaRlrGXQZdxl5GYIZhRmHGZAZkxmVGZ4ZoRmjGawZrxmxGboZvRm/GcgZyxnNGdYZ2RnbGeQZ5xnpGfIZ9Rn3GgAaAxoFGg4aERoTGhwaHxohGioaLRovGjwaPhpAGkIaSxp2Gngaehp8Gn4agBqDGoYaiRqMGo8akhqVGpgamxqeGqEapBqnGqoarRqvGrgauxq9GsYayRrLGtQa1xrZGuIa5RrnGvAa8xr1Gv4bARsDGwwbDxsRGxobHRsfGygbKxstGzYbORs7G0QbRxtJG1IbVRtXG2AbYxtlG24bcRtzG3wbfxuBG4objRuPG5gbmxudG6YbqRurG7Qbtxu5G8IbxRvHG9Qb1xvZG9sb5BwPHBIcFRwYHBscHhwhHCQcJxwqHC0cMBwzHDYcORw8HD8cQhxFHEgcSxxNHFYcWRxbHGQcZxxpHHIcdRx3HIAcgxyFHI4ckRyTHJwcnxyhHKocrRyvHLgcuxy9HMYcyRzLHNQc1xzZHOIc5RznHPAc8xz1HP4dAR0DHQwdDx0RHRodHR0fHSgdKx0tHTYdOR07HUQdRx1JHVIdVR1XHWAdYx1lHXIddR13HXkdgh2tHbAdsx22HbkdvB2/HcIdxR3IHcsdzh3RHdQd1x3aHd0d4B3jHeYd6R3rHfQd9x35HgIeBR4HHhAeEx4VHh4eIR4jHiweLx4xHjoePR4/HkgeSx5NHlYeWR5bHmQeZx5pHnIedR53HoAegx6FHo4ekR6THpwenx6hHqoerR6vHrgeux69HsYeyR7LHtQe1x7ZHuIe5R7nHvAe8x71Hv4fAR8DHxAfEx8VHxcfIB9LH04fUR9UH1cfWh9dH2AfYx9mH2kfbB9vH3IfdR94H3sffh+BH4Qfhx+JH5IflR+XH6Afox+lH64fsR+zH7wfvx/BH8ofzR/PH9gf2x/dH+Yf6R/rH/Qf9x/5IAIgBSAHIBAgEyAVIB4gISAjICwgLyAxIDogPSA/IEggSyBNIFYgWSBbIGQgZyBpIHIgdSB3IIAggyCFII4gkSCTIJwgnyChIK4gsSCzILUgviDpIOwg7yDyIPUg+CD7IP4hASEEIQchCiENIRAhEyEWIRkhHCEfISIhJSEnITAhMyE1IT4hQSFDIUwhTyFRIVohXSFfIWghayFtIXYheSF7IYQhhyGJIZIhlSGXIaAhoyGlIa4hsSGzIbwhvyHBIcohzSHPIdgh2yHdIeYh6SHrIfQh9yH5IgIiBSIHIhAiEyIVIh4iISIjIiwiLyIxIjoiPSI/IkwiTyJRIlMiXCKHIooijSKQIpMiliKZIpwinyKiIqUiqCKrIq4isSK0IrciuiK9IsAiwyLFIs4i0SLTItwi3yLhIuoi7SLvIvgi+yL9IwYjCSMLIxQjFyMZIyIjJSMnIzAjMyM1Iz4jQSNDI0wjTyNRI1ojXSNfI2gjayNtI3YjeSN7I4QjhyOJI5IjlSOXI6AjoyOlI64jsSOzI7wjvyPBI8ojzSPPI9gj2yPdI+oj7SPvI/Ej+iQlJCgkKyQuJDEkNCQ3JDokPSRAJEMkRiRJJEwkTyRSJFUkWCRbJF4kYSRjJGwkbyRxJHokfSR/JIgkiySNJJYkmSSbJKQkpySpJLIktSS3JMAkwyTFJM4k0STTJNwk3yThJOok7STvJPgk+yT9JQYlCSULJRQlFyUZJSIlJSUnJTAlMyU1JT4lQSVDJUwlTyVRJVolXSVfJWglayVtJXYleSV7JYgliyWNJY8lmCXDJcYlySXMJc8l0iXVJdgl2yXeJeEl5CXnJeol7SXwJfMl9iX5Jfwl/yYBJgomDSYPJhgmGyYdJiYmKSYrJjQmNyY5JkImRSZHJlAmUyZVJl4mYSZjJmwmbyZxJnomfSZ/JogmiyaNJpYmmSabJqQmpyapJrImtSa3JsAmwybFJs4m0SbTJtwm3ybhJuom7SbvJvgm+yb9JwYnCScLJxQnFycZJyYnKScrJy0nNidhJ2QnZydqJ20ncCdzJ3YneSd8J38ngieFJ4gniyeOJ5EnlCeXJ5onnSefJ6gnqyetJ7YnuSe7J8QnxyfJJ9In1SfXJ+An4yflJ+4n8SfzJ/wn/ygBKAooDSgPKBgoGygdKCYoKSgrKDQoNyg5KEIoRShHKFAoUyhVKF4oYShjKGwobyhxKHoofSh/KIgoiyiNKJYomSibKKQopyipKLIotSi3KMQoxyjJKMso1Cj/KQIpBSkIKQspDikRKRQpFykaKR0pICkjKSYpKSksKS8pMik1KTgpOyk9KUYpSSlLKVQpVylZKWIpZSlnKXApcyl1KX4pgSmDKYwpjymRKZopnSmfKagpqymtKbYpuSm7KcQpxynJKdIp1SnXKeAp4ynlKe4p8SnzKfwp/yoBKgoqDSoPKhgqGyodKiYqKSorKjQqNyo5KkIqRSpHKlAqUypVKmIqZSpnKmkqciqdKqAqoyqmKqkqrCqvKrIqtSq4KrsqvirBKsQqxyrKKs0q0CrTKtYq2SrbKuQq5yrpKvIq9Sr3KwArAysFKw4rESsTKxwrHyshKyorLSsvKzgrOys9K0YrSStLK1QrVytZK2IrZStnK3Arcyt1K34rgSuDK4wrjyuRK5ornSufK6grqyutK7YruSu7K8QrxyvJK9Ir1SvXK+Ar4yvlK+4r8SvzLAAsAywFLAcsECw7LD4sQSxELEcsSixNLFAsUyxWLFksXCxfLGIsZSxoLGssbixxLHQsdyx5LIIshSyHLJAskyyVLJ4soSyjLKwsryyxLLosvSy/LMgsyyzNLNYs2SzbLOQs5yzpLPIs9Sz3LQAtAy0FLQ4tES0TLRwtHy0hLSotLS0vLTgtOy09LUYtSS1LLVQtVy1ZLWItZS1nLXAtcy11LX4tgS2DLYwtjy2RLZ4toS2jLaUtri3ZLdwt3y3iLeUt6C3rLe4t8S30Lfct+i39LgAuAy4GLgkuDC4PLhIuFS4XLiAuIy4lLi4uMS4zLjwuPy5BLkouTS5PLlguWy5dLmYuaS5rLnQudy55LoIuhS6HLpAuky6VLp4uoS6jLqwury6xLrouvS6/Lsguyy7NLtYu2S7bLuQu5y7pLvIu9S73LwAvAy8FLw4vES8TLxwvHy8hLyovLS8vLzwvPy9BL0MvTC93L3ovfS+AL4Mvhi+JL4wvjy+SL5UvmC+bL54voS+kL6cvqi+tL7Avsy+1L74vwS/DL8wvzy/RL9ov3S/fL+gv6y/tL/Yv+S/7MAQwBzAJMBIwFTAXMCAwIzAlMC4wMTAzMDwwPzBBMEowTTBPMFgwWzBdMGYwaTBrMHQwdzB5MIIwhTCHMJAwkzCVMJ4woTCjMKwwrzCxMLowvTC/MMgwyzDNMNow3TDfMOEw6jEVMRgxGzEeMSExJDEnMSoxLTEwMTMxNjE5MTwxPzFCMUUxSDFLMU4xUTFTMVwxXzFhMWoxbTFvMXgxezF9MYYxiTGLMZQxlzGZMaIxpTGnMbAxszG1Mb4xwTHDMcwxzzHRMdox3THfMegx6zHtMfYx+TH7MgQyBzIJMhIyFTIXMiAyIzIlMi4yMTIzMjwyPzJBMkoyTTJPMlgyWzJdMmYyaTJrMngyezJ9Mn8yiDKzMrYyuTK8Mr8ywjLFMsgyyzLOMtEy1DLXMtoy3TLgMuMy5jLpMuwy7zLxMvoy/TL/MwgzCzMNMxYzGTMbMyQzJzMpMzIzNTM3M0AzQzNFM04zUTNTM1wzXzNhM2ozbTNvM3gzezN9M4YziTOLM5QzlzOZM6IzpTOnM7AzszO1M74zwTPDM8wzzzPRM9oz3TPfM+gz6zPtM/Yz+TP7NAQ0BzQJNBY0GTQbNB00JjRRNFQ0VzRaNF00YDRjNGY0aTRsNG80cjR1NHg0ezR+NIE0hDSHNIo0jTSPNJg0mzSdNKY0qTSrNLQ0tzS5NMI0xTTHNNA00zTVNN404TTjNOw07zTxNPo0/TT/NQg1CzUNNRY1GTUbNSQ1JzUpNTI1NTU3NUA1QzVFNU41UTVTNVw1XzVhNWo1bTVvNXg1ezV9NYY1iTWLNZQ1lzWZNaI1pTWnNbQ1tzW5Nbs1xDXvNfI19TX4Nfs1/jYBNgQ2BzYKNg02EDYTNhY2GTYcNh82IjYlNig2KzYtNjY2OTY7NkQ2RzZJNlI2VTZXNmA2YzZlNm42cTZzNnw2fzaBNoo2jTaPNpg2mzadNqY2qTarNrQ2tza5NsI2xTbHNtA20zbVNt424TbjNuw27zbxNvo2/Tb/Nwg3CzcNNxY3GTcbNyQ3JzcpNzI3NTc3N0A3QzdFN043ezd+N4E3gzeGN4k3jDePN5I3lTeYN5s3njehN6M3pjepN6s3rTewN7M3tje4N8U3yDfKN9M3/jgBOAM4BTgHOAk4CzgNOA84ETgTOBU4FzgZOBs4HTgfOCE4IzglOCc4KTgyODU4NzhEOEc4SThSOIM4hTiHOIo4jDiOOJA4kziWOJk4nDifOKE4pDinOKo4rTiwOLM4tji5OLw4vzjCOMQ4zTjQONI42zjeOOA46TjsOO44+zj+OQA5CTkwOTM5Njk5OTw5PzlBOUQ5RzlKOU05UDlTOVY5WTlcOV85YjllOWc5dDl3OXk5gjmpOaw5rjmxObQ5tzm6Ob05wDnDOcY5yTnMOc850jnVOdg52jndOd857DnvOfE5+jonOio6LTowOjM6NTo4Ojo6PTpAOkM6RTpIOks6TjpROlQ6VzpaOl06YDpjOmU6bjpxOnM6fDp/OoE6jjqROpM6lTqeOsE6xDrHOso6zTrQOtM61jrZOtw63zriOuU66DrrOu468TrzOvw6/zsBOwo7DTsPOxg7GzsdOyY7KTsrOzQ7Nzs5O0I7RTtHO1A7UztVO147YTtjO2w7bztxO3o7fTt/O4g7izuNO5Y7mTubO6Q7pzupO7I7tTu3O8A7wzvFO8470TvTO+A74zvlO+c78DwZPBw8HzwiPCU8KDwrPC48MTw0PDc8Ojw9PEA8QzxGPEk8TDxPPFI8VDxdPGA8YjxrPG48cDx5PHw8fjyHPIo8jDyVPJg8mjyjPKY8qDyxPLQ8tjy/PMI8xDzNPNA80jzbPN484DzpPOw87jz3PPo8/D0FPQg9Cj0TPRY9GD0hPSQ9Jj0vPTI9ND09PUA9Qj1LPU49UD1ZPVw9Xj1rPW49cD15Pag9qz2uPbE9tD23Pbo9vT3APcI9xT3IPcs9zj3RPdQ91z3aPd094D3jPeY96T3rPfQ99z35PgI+BT4HPhQ+Fz4ZPiI+TT5QPlM+VT5YPls+Xj5hPmQ+Zz5qPm0+cD5zPnU+eD57Pn4+gT6EPoc+iT6SPpU+lz6kPqc+qT6yPuM+5j7pPuw+7z7yPvU++D77Pv4/AT8EPwY/CT8MPw8/Ej8VPxg/Gz8dPyA/Iz8mPyg/MT80PzY/Pz9CP0Q/TT9QP1I/Xz9iP2Q/bT+SP5U/mD+bP54/oT+kP6c/qj+tP68/sj+1P7g/uz++P8A/wz/FP9I/1T/XP+BAC0AOQBFAFEAXQBpAHEAfQCJAJEAnQClALEAvQDJANUA4QDtAPkBBQENARUBOQFFAU0BcQF9AYUBuQHFAc0B8QKtArkCwQLNAtkC4QLtAvkDBQMRAx0DKQMxAzkDRQNRA10DaQN1A4EDiQORA5kDoQPFA9ED2QP9BAkEEQQ1BEEESQR9BIkEkQSZBL0FSQVVBWEFbQV5BYUFkQWdBakFtQXBBc0F2QXlBfEF/QYJBhEGNQZBBkkGbQZ5BoEGpQaxBrkG3QbpBvEHFQchBykHTQdZB2EHhQeRB5kHvQfJB9EH9QgBCAkILQg5CEEIZQhxCHkInQipCLEI1QjhCOkJDQkZCSEJRQlRCVkJfQmJCZEJxQnRCdkJ/QqpCrUKwQrNCtkK5QrxCvkLBQsRCx0LKQs1C0ELTQtZC2ELbQt5C4ELjQuVC7kLxQvNC/EL/QwFDCkMNQw9DGEMbQx1DKkMtQy9DOENfQ2JDZUNnQ2pDbUNwQ3NDdkN5Q3xDf0OCQ4VDiEOLQ45DkUOTQ5VDnkOhQ6NDrEOvQ7FDvkPBQ8NDzEP3Q/pD/UQARANEBkQJRAxED0QSRBVEGEQbRB5EIUQkRCdEKkQtRDBEM0Q1RD5EQURDRFBEUkRVRF5EZURnRHBEm0SeRKFEpESnRKpErUSwRLNEtkS5RLxEv0TCRMVEyETLRM5E0UTURNdE2UTiRORE9UT3RPlFAkUERRFFE0UWRR9FJEUmRTNFNUU4RUFFRkVIRVlFW0VdRWZFaEVxRXNFfEV+RYdFiUWaRZxFpUWnRbBFskW/RcFFxEXNRdRF1kXjReVF6EXxRfZF+EYJRgtGDUYWRhhGJUYnRipGM0Y6RjxGSUZLRk5GV0ZgRmJGc0Z1RndGgEarRq5GsUa0RrdGuka9RsBGw0bGRslGzEbPRtJG1UbYRttG3kbhRuRG50bpRvJG9EcBRwNHBkcPRxRHFkcnRylHK0c8Rz5HQEdNR09HUkdbR2BHYkdvR3FHdEd9R4RHhkePR5FHmkecR61Hr0e4R7pHx0fJR8xH1UfaR9xH6UfrR+5H90f8R/5IB0gJSBZIGEgbSCRIKUgrSDhIOkg9SEZIT0hRSF5IYEhjSGxIdUh3SIBIgkiPSJFIlEidSKRIpkizSLVIuEjBSMZIyEjRSNNI3EkJSQxJD0kSSRVJGEkbSR5JIUkkSSdJKkktSTBJM0k2STlJPEk/SUJJRUlISUpJU0lWSVlJW0lkSWtJbklxSXRJdkl/SYBJg0mMSZFJmkmbSZ1JpkmnSalJskm3SbpJvUm/SchJzUnQSdNJ1UneSeFJ5EnmSe9J9kn5SfxJ/0oBSgpKC0oNShZKG0oeSiFKI0osSjNKNko5SjxKPkpHSlBKU0pWSllKXEpeSmdKbEpvSnJKdEp9SoBKg0qFSpJKlEqXSqBKp0qpSrJKuUq8Sr9KwkrESs1K2krfSuxK9UsESwlLGEsqSy9LNAAAAAAAAAICAAAAAAAADfoAAAAAAAAAAAAAAAAAAEs2 \ No newline at end of file +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BvwHBAcMBxQHHAckBywHeAfcCDQIcAiQCKQJCAlcCbQJ7ApMCpwKwArECswK8AscC0ALfAuYC9QL9AwYDFwMiAy8DOAM6AzwDRQNZA2ADdAN/A4gDkQOTA5UDlwOZA5sDrAOuA7ADuQO7A70DxgPIA9kD2wPdA+YD8QPzA/UD9wP5A/sD/QQGBAcECQQSBBMEFQQeBB8EIQQqBCsELQQ2BDcEOQRCBE0ETwRRBFMEVQRXBFkEZgRsBHYEeAR7BH0EhgSRBJMElQSXBJkEmwSdBKYErQSwBLIEuwTOBNME5gTvBPIE9AT9BQAFAgULBQ4FEAUZBRwFHgUnBT0FQgVYBWUFZwVqBWwFdQWABYIFhAWGBYgFigWMBZUFmAWaBaMFpgWoBbEFtAW2Bb8FwgXEBc0F0AXSBd8F4QXkBeYF7wX6BfwF/gYABgIGBAYGBg8GEgYUBh0GIAYiBisGLgYwBjkGPAY+BkcGSgZMBlkGWwZeBmAGaQZ0BnYGeAZ6BnwGfgaABokGjAaOBpcGmgacBqUGqAaqBrMGtga4BsEGxAbGBtMG1QbYBtoG4wbuBvAG8gb0BvYG+Ab6BwMHBgcIBxEHFAcWBx8HIgckBy0HMAcyBzsHPgdAB0kHTgdXB2AHYgdkB2YHaAdqB3cHeQd7B4QHkQeTB5UHlweZB5sHnQefB6gHqwetB7oHvAe/B8EHygfVB9cH2QfbB90H3wfhB+oH7QfvB/gH+wf9CAYICQgLCBQIFwgZCCIIJQgnCDQINgg4CEEITAhOCFAIUghUCFYIWAhlCGcIaQhyCH8IgQiDCIUIhwiJCIsIjQiWCJkImwikCKYIrwi6CLwIvgjACMIIxAjGCM8I0QjaCNwI5QjnCPAI8gj7CP0JBgkRCRMJFQkXCRkJGwkdCSYJKAkxCTMJPAk+CUcJSQlSCVQJXQlmCWgJaglsCW4JcAl5CXwJfgmACYkJigmMCZUJlgmYCaEJpAmmCagJuQm7CcQJxwnJCcsJ1AnhCeYJ8wn8CgsKEAofCjEKNgo7AAAAAAAAAgIAAAAAAAABrAAAAAAAAAAAAAAAAAAACj0= \ No newline at end of file From 35056f708b0d58fdd243f6195f0970dc273fb2ab Mon Sep 17 00:00:00 2001 From: Adlai Holler Date: Thu, 23 Jun 2016 16:57:09 -0700 Subject: [PATCH 03/43] [ASDataController] Improve update handling --- AsyncDisplayKit/ASTableView.mm | 6 ++ .../Details/ASChangeSetDataController.m | 24 ++--- .../Details/ASCollectionDataController.mm | 48 --------- .../Details/ASDataController+Subclasses.h | 44 --------- AsyncDisplayKit/Details/ASDataController.mm | 70 +------------ .../Details/NSIndexSet+ASHelpers.h | 4 +- .../Details/NSIndexSet+ASHelpers.m | 14 +++ .../Private/_ASHierarchyChangeSet.h | 4 +- .../Private/_ASHierarchyChangeSet.m | 99 ++++++++++--------- AsyncDisplayKitTests/ASTableViewThrashTests.m | 15 ++- 10 files changed, 95 insertions(+), 233 deletions(-) diff --git a/AsyncDisplayKit/ASTableView.mm b/AsyncDisplayKit/ASTableView.mm index 13e77c1a52..c0dfd1fc15 100644 --- a/AsyncDisplayKit/ASTableView.mm +++ b/AsyncDisplayKit/ASTableView.mm @@ -456,18 +456,21 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell"; - (void)insertSections:(NSIndexSet *)sections withRowAnimation:(UITableViewRowAnimation)animation { ASDisplayNodeAssertMainThread(); + if (sections.count == 0) { return; } [_dataController insertSections:sections withAnimationOptions:animation]; } - (void)deleteSections:(NSIndexSet *)sections withRowAnimation:(UITableViewRowAnimation)animation { ASDisplayNodeAssertMainThread(); + if (sections.count == 0) { return; } [_dataController deleteSections:sections withAnimationOptions:animation]; } - (void)reloadSections:(NSIndexSet *)sections withRowAnimation:(UITableViewRowAnimation)animation { ASDisplayNodeAssertMainThread(); + if (sections.count == 0) { return; } [_dataController reloadSections:sections withAnimationOptions:animation]; } @@ -480,18 +483,21 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell"; - (void)insertRowsAtIndexPaths:(NSArray *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation { ASDisplayNodeAssertMainThread(); + if (indexPaths.count == 0) { return; } [_dataController insertRowsAtIndexPaths:indexPaths withAnimationOptions:animation]; } - (void)deleteRowsAtIndexPaths:(NSArray *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation { ASDisplayNodeAssertMainThread(); + if (indexPaths.count == 0) { return; } [_dataController deleteRowsAtIndexPaths:indexPaths withAnimationOptions:animation]; } - (void)reloadRowsAtIndexPaths:(NSArray *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation { ASDisplayNodeAssertMainThread(); + if (indexPaths.count == 0) { return; } [_dataController reloadRowsAtIndexPaths:indexPaths withAnimationOptions:animation]; } diff --git a/AsyncDisplayKit/Details/ASChangeSetDataController.m b/AsyncDisplayKit/Details/ASChangeSetDataController.m index 57fb476c79..7802a6c1d5 100644 --- a/AsyncDisplayKit/Details/ASChangeSetDataController.m +++ b/AsyncDisplayKit/Details/ASChangeSetDataController.m @@ -48,30 +48,16 @@ [super beginUpdates]; - for (_ASHierarchyItemChange *change in [_changeSet itemChangesOfType:_ASHierarchyChangeTypeReload]) { - [super deleteRowsAtIndexPaths:change.indexPaths withAnimationOptions:change.animationOptions]; - } + NSAssert([_changeSet itemChangesOfType:_ASHierarchyChangeTypeReload].count == 0, @"Expected reload item changes to have been converted into insert/deletes."); + NSAssert([_changeSet sectionChangesOfType:_ASHierarchyChangeTypeReload].count == 0, @"Expected reload section changes to have been converted into insert/deletes."); for (_ASHierarchyItemChange *change in [_changeSet itemChangesOfType:_ASHierarchyChangeTypeDelete]) { [super deleteRowsAtIndexPaths:change.indexPaths withAnimationOptions:change.animationOptions]; } - for (_ASHierarchySectionChange *change in [_changeSet sectionChangesOfType:_ASHierarchyChangeTypeReload]) { - [super deleteSections:change.indexSet withAnimationOptions:change.animationOptions]; - } - for (_ASHierarchySectionChange *change in [_changeSet sectionChangesOfType:_ASHierarchyChangeTypeDelete]) { [super deleteSections:change.indexSet withAnimationOptions:change.animationOptions]; } - - // TODO: Shouldn't reloads be processed before deletes, since deletes affect - // the index space and reloads don't? - for (_ASHierarchySectionChange *change in [_changeSet sectionChangesOfType:_ASHierarchyChangeTypeReload]) { - NSIndexSet *newIndexes = [change.indexSet as_indexesByMapping:^(NSUInteger idx) { - return [_changeSet newSectionForOldSection:idx]; - }]; - [super insertSections:newIndexes withAnimationOptions:change.animationOptions]; - } for (_ASHierarchySectionChange *change in [_changeSet sectionChangesOfType:_ASHierarchyChangeTypeInsert]) { [super insertSections:change.indexSet withAnimationOptions:change.animationOptions]; @@ -123,7 +109,8 @@ if ([self batchUpdating]) { [_changeSet reloadSections:sections animationOptions:animationOptions]; } else { - [super reloadSections:sections withAnimationOptions:animationOptions]; + [super deleteSections:sections withAnimationOptions:animationOptions]; + [super insertSections:sections withAnimationOptions:animationOptions]; } } @@ -166,7 +153,8 @@ if ([self batchUpdating]) { [_changeSet reloadItems:indexPaths animationOptions:animationOptions]; } else { - [super reloadRowsAtIndexPaths:indexPaths withAnimationOptions:animationOptions]; + [super deleteRowsAtIndexPaths:indexPaths withAnimationOptions:animationOptions]; + [super insertRowsAtIndexPaths:indexPaths withAnimationOptions:animationOptions]; } } diff --git a/AsyncDisplayKit/Details/ASCollectionDataController.mm b/AsyncDisplayKit/Details/ASCollectionDataController.mm index b54583c2a2..df0e7d592b 100644 --- a/AsyncDisplayKit/Details/ASCollectionDataController.mm +++ b/AsyncDisplayKit/Details/ASCollectionDataController.mm @@ -115,30 +115,6 @@ } } -- (void)prepareForReloadSections:(NSIndexSet *)sections -{ - for (NSString *kind in [self supplementaryKinds]) { - NSMutableArray *contexts = [NSMutableArray array]; - [self _populateSupplementaryNodesOfKind:kind withSections:sections mutableContexts:contexts]; - _pendingContexts[kind] = contexts; - } -} - -- (void)willReloadSections:(NSIndexSet *)sections -{ - NSArray *keys = _pendingContexts.allKeys; - for (NSString *kind in keys) { - NSMutableArray *contexts = _pendingContexts[kind]; - NSArray *indexPaths = ASIndexPathsForMultidimensionalArrayAtIndexSet([self editingNodesOfKind:kind], sections); - [self deleteNodesOfKind:kind atIndexPaths:indexPaths completion:nil]; - // reinsert the elements - [self batchLayoutNodesFromContexts:contexts ofKind:kind completion:^(NSArray *nodes, NSArray *indexPaths) { - [self insertNodes:nodes ofKind:kind atIndexPaths:indexPaths completion:nil]; - }]; - [_pendingContexts removeObjectForKey:kind]; - } -} - - (void)willMoveSection:(NSInteger)section toSection:(NSInteger)newSection { for (NSString *kind in [self supplementaryKinds]) { @@ -187,30 +163,6 @@ } } -- (void)prepareForReloadRowsAtIndexPaths:(NSArray *)indexPaths -{ - for (NSString *kind in [self supplementaryKinds]) { - NSMutableArray *contexts = [NSMutableArray array]; - [self _populateSupplementaryNodesOfKind:kind atIndexPaths:indexPaths mutableContexts:contexts]; - _pendingContexts[kind] = contexts; - } -} - -- (void)willReloadRowsAtIndexPaths:(NSArray *)indexPaths -{ - NSArray *keys = _pendingContexts.allKeys; - for (NSString *kind in keys) { - NSMutableArray *contexts = _pendingContexts[kind]; - - [self deleteNodesOfKind:kind atIndexPaths:indexPaths completion:nil]; - // reinsert the elements - [self batchLayoutNodesFromContexts:contexts ofKind:kind completion:^(NSArray *nodes, NSArray *indexPaths) { - [self insertNodes:nodes ofKind:kind atIndexPaths:indexPaths completion:nil]; - }]; - [_pendingContexts removeObjectForKey:kind]; - } -} - - (void)_populateSupplementaryNodesOfKind:(NSString *)kind withMutableContexts:(NSMutableArray *)contexts { id environment = [self.environmentDelegate dataControllerEnvironment]; diff --git a/AsyncDisplayKit/Details/ASDataController+Subclasses.h b/AsyncDisplayKit/Details/ASDataController+Subclasses.h index d837540362..099a9bfe45 100644 --- a/AsyncDisplayKit/Details/ASDataController+Subclasses.h +++ b/AsyncDisplayKit/Details/ASDataController+Subclasses.h @@ -128,28 +128,6 @@ typedef void (^ASDataControllerCompletionBlock)(NSArray *nodes, NS */ - (void)willDeleteSections:(NSIndexSet *)sections; -/** - * Notifies the subclass to perform any work needed before the given sections will be reloaded. - * - * @discussion This method will be performed before the data controller enters its editing queue, usually on the main - * thread. The data source is locked at this point and accessing it is safe. Use this method to set up any nodes or - * data stores before entering into editing the backing store on a background thread. - * - * @param sections Indices of sections to be reloaded - */ -- (void)prepareForReloadSections:(NSIndexSet *)sections; - -/** - * Notifies the subclass that the data controller will reload the sections in the given index set - * - * @discussion This method will be performed on the data controller's editing background queue before the parent's - * concrete implementation. This is a great place to perform any additional transformations like supplementary views - * or header/footer nodes. - * - * @param sections Indices of sections to be reloaded - */ -- (void)willReloadSections:(NSIndexSet *)sections; - /** * Notifies the subclass that the data controller will move a section to a new position * @@ -206,26 +184,4 @@ typedef void (^ASDataControllerCompletionBlock)(NSArray *nodes, NS */ - (void)willDeleteRowsAtIndexPaths:(NSArray *)indexPaths; -/** - * Notifies the subclass to perform any work needed before the given rows will be reloaded. - * - * @discussion This method will be performed before the data controller enters its editing queue, usually on the main - * thread. The data source is locked at this point and accessing it is safe. Use this method to set up any nodes or - * data stores before entering into editing the backing store on a background thread. - * - * @param indexPaths Index paths for the rows to be reloaded. - */ -- (void)prepareForReloadRowsAtIndexPaths:(NSArray *)indexPaths; - -/** - * Notifies the subclass that the data controller will reload the rows at the given index paths. - * - * @discussion This method will be performed on the data controller's editing background queue before the parent's - * concrete implementation. This is a great place to perform any additional transformations like supplementary views - * or header/footer nodes. - * - * @param indexPaths Index paths for the rows to be reloaded. - */ -- (void)willReloadRowsAtIndexPaths:(NSArray *)indexPaths; - @end diff --git a/AsyncDisplayKit/Details/ASDataController.mm b/AsyncDisplayKit/Details/ASDataController.mm index 86967fc99a..74869de0d7 100644 --- a/AsyncDisplayKit/Details/ASDataController.mm +++ b/AsyncDisplayKit/Details/ASDataController.mm @@ -65,6 +65,7 @@ static void *kASSizingQueueContext = &kASSizingQueueContext; if (!(self = [super init])) { return nil; } + ASDisplayNodeAssert(![self isMemberOfClass:[ASDataController class]], @"ASDataController is an abstract class and should not be instantiated. Instantiate a subclass instead."); _completedNodes = [NSMutableDictionary dictionary]; _editingNodes = [NSMutableDictionary dictionary]; @@ -661,29 +662,7 @@ static void *kASSizingQueueContext = &kASSizingQueueContext; - (void)reloadSections:(NSIndexSet *)sections withAnimationOptions:(ASDataControllerAnimationOptions)animationOptions { - [self performEditCommandWithBlock:^{ - ASDisplayNodeAssertMainThread(); - LOG(@"Edit Command - reloadSections: %@", sections); - - [_editingTransactionQueue waitUntilAllOperationsAreFinished]; - - NSArray *contexts= [self _populateFromDataSourceWithSectionIndexSet:sections]; - - [self prepareForReloadSections:sections]; - - [_editingTransactionQueue addOperationWithBlock:^{ - [self willReloadSections:sections]; - - NSArray *indexPaths = ASIndexPathsForMultidimensionalArrayAtIndexSet(_editingNodes[ASDataControllerRowNodeKind], sections); - - LOG(@"Edit Transaction - reloadSections: updatedIndexPaths: %@, indexPaths: %@, _editingNodes: %@", updatedIndexPaths, indexPaths, ASIndexPathsForTwoDimensionalArray(_editingNodes[ASDataControllerRowNodeKind])); - - [self _deleteNodesAtIndexPaths:indexPaths withAnimationOptions:animationOptions]; - - // reinsert the elements - [self _batchLayoutNodesFromContexts:contexts withAnimationOptions:animationOptions]; - }]; - }]; + ASDisplayNodeAssert(NO, @"ASDataController does not support %@. Call this on ASChangeSetDataController the reload will be broken into delete & insert.", NSStringFromSelector(_cmd)); } - (void)moveSection:(NSInteger)section toSection:(NSInteger)newSection withAnimationOptions:(ASDataControllerAnimationOptions)animationOptions @@ -781,16 +760,6 @@ static void *kASSizingQueueContext = &kASSizingQueueContext; // Optional template hook for subclasses (See ASDataController+Subclasses.h) } -- (void)prepareForReloadRowsAtIndexPaths:(NSArray *)indexPaths -{ - // Optional template hook for subclasses (See ASDataController+Subclasses.h) -} - -- (void)willReloadRowsAtIndexPaths:(NSArray *)indexPaths -{ - // Optional template hook for subclasses (See ASDataController+Subclasses.h) -} - #pragma mark - Row Editing (External API) - (void)insertRowsAtIndexPaths:(NSArray *)indexPaths withAnimationOptions:(ASDataControllerAnimationOptions)animationOptions @@ -853,40 +822,7 @@ static void *kASSizingQueueContext = &kASSizingQueueContext; - (void)reloadRowsAtIndexPaths:(NSArray *)indexPaths withAnimationOptions:(ASDataControllerAnimationOptions)animationOptions { - [self performEditCommandWithBlock:^{ - ASDisplayNodeAssertMainThread(); - LOG(@"Edit Command - reloadRows: %@", indexPaths); - - [_editingTransactionQueue waitUntilAllOperationsAreFinished]; - - NSMutableArray *contexts = [[NSMutableArray alloc] initWithCapacity:indexPaths.count]; - - // Sort indexPath to avoid messing up the index when deleting - // FIXME: Shouldn't deletes be sorted in descending order? - NSArray *sortedIndexPaths = [indexPaths sortedArrayUsingSelector:@selector(compare:)]; - - id environment = [self.environmentDelegate dataControllerEnvironment]; - ASEnvironmentTraitCollection environmentTraitCollection = environment.environmentTraitCollection; - - for (NSIndexPath *indexPath in sortedIndexPaths) { - ASCellNodeBlock nodeBlock = [_dataSource dataController:self nodeBlockAtIndexPath:indexPath]; - ASSizeRange constrainedSize = [self constrainedSizeForNodeOfKind:ASDataControllerRowNodeKind atIndexPath:indexPath]; - [contexts addObject:[[ASIndexedNodeContext alloc] initWithNodeBlock:nodeBlock - indexPath:indexPath - constrainedSize:constrainedSize - environmentTraitCollection:environmentTraitCollection]]; - } - - [self prepareForReloadRowsAtIndexPaths:indexPaths]; - - [_editingTransactionQueue addOperationWithBlock:^{ - [self willReloadRowsAtIndexPaths:indexPaths]; - - LOG(@"Edit Transaction - reloadRows: %@", indexPaths); - [self _deleteNodesAtIndexPaths:sortedIndexPaths withAnimationOptions:animationOptions]; - [self _batchLayoutNodesFromContexts:contexts withAnimationOptions:animationOptions]; - }]; - }]; + ASDisplayNodeAssert(NO, @"ASDataController does not support %@. Call this on ASChangeSetDataController and the reload will be broken into delete & insert.", NSStringFromSelector(_cmd)); } - (void)relayoutAllNodes diff --git a/AsyncDisplayKit/Details/NSIndexSet+ASHelpers.h b/AsyncDisplayKit/Details/NSIndexSet+ASHelpers.h index fc8fc6cafe..54e9ac0126 100644 --- a/AsyncDisplayKit/Details/NSIndexSet+ASHelpers.h +++ b/AsyncDisplayKit/Details/NSIndexSet+ASHelpers.h @@ -10,7 +10,7 @@ @interface NSIndexSet (ASHelpers) -- (NSIndexSet *)as_indexesByMapping:(NSUInteger (^)(NSUInteger))block; +- (NSIndexSet *)as_indexesByMapping:(NSUInteger (^)(NSUInteger idx))block; - (NSIndexSet *)as_intersectionWithIndexes:(NSIndexSet *)indexes; @@ -20,4 +20,6 @@ /// If you've got an old index, and you insert items using this index set, this returns the new index. - (NSUInteger)as_indexByInsertingItemsBelowIndex:(NSUInteger)index; +- (NSString *)as_smallDescription; + @end diff --git a/AsyncDisplayKit/Details/NSIndexSet+ASHelpers.m b/AsyncDisplayKit/Details/NSIndexSet+ASHelpers.m index 183ae959e4..feac7ec8d0 100644 --- a/AsyncDisplayKit/Details/NSIndexSet+ASHelpers.m +++ b/AsyncDisplayKit/Details/NSIndexSet+ASHelpers.m @@ -59,4 +59,18 @@ return newIndex; } +- (NSString *)as_smallDescription +{ + NSMutableString *result = [NSMutableString stringWithString:@"{ "]; + [self enumerateRangesUsingBlock:^(NSRange range, BOOL * _Nonnull stop) { + if (range.length == 1) { + [result appendFormat:@"%lu ", (unsigned long)range.location]; + } else { + [result appendFormat:@"%lu-%lu ", (unsigned long)range.location, (unsigned long)NSMaxRange(range)]; + } + }]; + [result appendString:@"}"]; + return result; +} + @end diff --git a/AsyncDisplayKit/Private/_ASHierarchyChangeSet.h b/AsyncDisplayKit/Private/_ASHierarchyChangeSet.h index d46d0a3622..9387a91d56 100644 --- a/AsyncDisplayKit/Private/_ASHierarchyChangeSet.h +++ b/AsyncDisplayKit/Private/_ASHierarchyChangeSet.h @@ -23,6 +23,8 @@ typedef NS_ENUM(NSInteger, _ASHierarchyChangeType) { _ASHierarchyChangeTypeInsert }; +NSString *NSStringFromASHierarchyChangeType(_ASHierarchyChangeType changeType); + @interface _ASHierarchySectionChange : NSObject // FIXME: Generalize this to `changeMetadata` dict? @@ -49,8 +51,6 @@ typedef NS_ENUM(NSInteger, _ASHierarchyChangeType) { @property (nonatomic, strong, readonly) NSIndexSet *deletedSections; /// @precondition The change set must be completed. @property (nonatomic, strong, readonly) NSIndexSet *insertedSections; -/// @precondition The change set must be completed. -@property (nonatomic, strong, readonly) NSIndexSet *reloadedSections; /** Get the section index after the update for the given section before the update. diff --git a/AsyncDisplayKit/Private/_ASHierarchyChangeSet.m b/AsyncDisplayKit/Private/_ASHierarchyChangeSet.m index 9b32376faf..26adef5cd1 100644 --- a/AsyncDisplayKit/Private/_ASHierarchyChangeSet.m +++ b/AsyncDisplayKit/Private/_ASHierarchyChangeSet.m @@ -13,6 +13,21 @@ #import "_ASHierarchyChangeSet.h" #import "ASInternalHelpers.h" #import "NSIndexSet+ASHelpers.h" +#import "ASAssert.h" + +NSString *NSStringFromASHierarchyChangeType(_ASHierarchyChangeType changeType) +{ + switch (changeType) { + case _ASHierarchyChangeTypeInsert: + return @"Insert"; + case _ASHierarchyChangeTypeDelete: + return @"Delete"; + case _ASHierarchyChangeTypeReload: + return @"Reload"; + default: + return @"(invalid)"; + } +} @interface _ASHierarchySectionChange () - (instancetype)initWithChangeType:(_ASHierarchyChangeType)changeType indexSet:(NSIndexSet *)indexSet animationOptions:(ASDataControllerAnimationOptions)animationOptions; @@ -37,21 +52,6 @@ + (void)sortAndCoalesceChanges:(NSMutableArray *)changes ignoringChangesInSections:(NSIndexSet *)sections; @end -@implementation NSIndexSet (ASHierarchyHelpers) - -- (NSIndexSet *)intersectionWithIndexes:(NSIndexSet *)indexes -{ - NSMutableIndexSet *result = [NSMutableIndexSet indexSet]; - [self enumerateRangesUsingBlock:^(NSRange range, BOOL * _Nonnull stop) { - [indexes enumerateRangesInRange:range options:kNilOptions usingBlock:^(NSRange range, BOOL * _Nonnull stop) { - [result addIndexesInRange:range]; - }]; - }]; - return result; -} - -@end - @interface _ASHierarchyChangeSet () @property (nonatomic, strong, readonly) NSMutableArray<_ASHierarchyItemChange *> *insertItemChanges; @@ -224,37 +224,30 @@ - (void)_sortAndCoalesceChangeArrays { @autoreleasepool { + + // Split reloaded section indexes into deletes and inserts + // Delete the old section, insert the new section it corresponds to. + for (_ASHierarchySectionChange *change in _reloadSectionChanges) { + NSIndexSet *newSections = [change.indexSet as_indexesByMapping:^(NSUInteger idx) { + NSUInteger newSec = [self newSectionForOldSection:idx]; + NSAssert(newSec != NSNotFound, nil); + return newSec; + }]; + + _ASHierarchySectionChange *deleteChange = [[_ASHierarchySectionChange alloc] initWithChangeType:_ASHierarchyChangeTypeDelete indexSet:change.indexSet animationOptions:change.animationOptions]; + [_deleteSectionChanges addObject:deleteChange]; + + _ASHierarchySectionChange *insertChange = [[_ASHierarchySectionChange alloc] initWithChangeType:_ASHierarchyChangeTypeInsert indexSet:newSections animationOptions:change.animationOptions]; + [_insertSectionChanges addObject:insertChange]; + } + + _reloadSectionChanges = nil; + [_ASHierarchySectionChange sortAndCoalesceChanges:_deleteSectionChanges]; [_ASHierarchySectionChange sortAndCoalesceChanges:_insertSectionChanges]; [_ASHierarchySectionChange sortAndCoalesceChanges:_reloadSectionChanges]; - - _deletedSections = [[_ASHierarchySectionChange allIndexesInSectionChanges:_deleteSectionChanges] copy]; - _insertedSections = [[_ASHierarchySectionChange allIndexesInSectionChanges:_insertSectionChanges] copy]; - _reloadedSections = [[_ASHierarchySectionChange allIndexesInSectionChanges:_reloadSectionChanges] copy]; - - NSIndexSet *deletedAndReloaded = [_deletedSections intersectionWithIndexes:_reloadedSections]; - NSAssert(deletedAndReloaded.count == 0, @"Request to delete and reload the same section(s): %@", deletedAndReloaded); - - // These are invalid old section indexes. - NSMutableIndexSet *deletedOrReloaded = [_deletedSections mutableCopy]; - [deletedOrReloaded addIndexes:_reloadedSections]; - - // These are invalid new section indexes. - NSMutableIndexSet *insertedOrReloaded = [_insertedSections mutableCopy]; - - // Get the new section that each reloaded section index corresponds to. - // Coalesce reload sections' indexes into deletes and inserts - [_reloadedSections enumerateIndexesUsingBlock:^(NSUInteger oldIndex, __unused BOOL * stop) { - NSUInteger newIndex = [self newSectionForOldSection:oldIndex]; - if (newIndex != NSNotFound) { - [insertedOrReloaded addIndex:newIndex]; - } - [deletedOrReloaded addIndex:oldIndex]; - }]; - - _deletedSections = deletedOrReloaded; - _insertedSections = insertedOrReloaded; - _reloadedSections = nil; + _deletedSections = [_ASHierarchySectionChange allIndexesInSectionChanges:_deleteSectionChanges]; + _insertedSections = [_ASHierarchySectionChange allIndexesInSectionChanges:_insertSectionChanges]; // reload items changes need to be adjusted so that we access the correct indexPaths in the datasource NSDictionary *insertedIndexPathsMap = [_ASHierarchyItemChange sectionToIndexSetMapFromChanges:_insertItemChanges ofType:_ASHierarchyChangeTypeInsert]; @@ -296,13 +289,17 @@ [_reloadItemChanges removeAllObjects]; // Ignore item deletes in reloaded/deleted sections. - [_ASHierarchyItemChange sortAndCoalesceChanges:_deleteItemChanges ignoringChangesInSections:deletedOrReloaded]; + [_ASHierarchyItemChange sortAndCoalesceChanges:_deleteItemChanges ignoringChangesInSections:_deletedSections]; // Ignore item inserts in reloaded(new)/inserted sections. - [_ASHierarchyItemChange sortAndCoalesceChanges:_insertItemChanges ignoringChangesInSections:insertedOrReloaded]; + [_ASHierarchyItemChange sortAndCoalesceChanges:_insertItemChanges ignoringChangesInSections:_insertedSections]; } } +- (NSString *)description +{ + return [NSString stringWithFormat:@"<%@ %p: deletedSections=%@, insertedSections=%@, deletedItems=%@, insertedItems=%@>", NSStringFromClass(self.class), self, _deletedSections, _insertedSections, _deleteItemChanges, _insertItemChanges]; +} @end @@ -313,6 +310,7 @@ { self = [super init]; if (self) { + ASDisplayNodeAssert(indexSet.count > 0, @"Request to create _ASHierarchySectionChange with no sections!"); _changeType = changeType; _indexSet = indexSet; _animationOptions = animationOptions; @@ -385,6 +383,11 @@ return indexes; } +- (NSString *)description +{ + return [NSString stringWithFormat:@"<%@: anim=%lu, type=%@, indexes=%@>", NSStringFromClass(self.class), (unsigned long)_animationOptions, NSStringFromASHierarchyChangeType(_changeType), [self.indexSet as_smallDescription]]; +} + @end @implementation _ASHierarchyItemChange @@ -393,6 +396,7 @@ { self = [super init]; if (self) { + ASDisplayNodeAssert(indexPaths.count > 0, @"Request to create _ASHierarchyItemChange with no items!"); _changeType = changeType; if (presorted) { _indexPaths = indexPaths; @@ -489,4 +493,9 @@ [changes setArray:result]; } +- (NSString *)description +{ + return [NSString stringWithFormat:@"<%@: anim=%lu, type=%@, indexPaths=%@>", NSStringFromClass(self.class), (unsigned long)_animationOptions, NSStringFromASHierarchyChangeType(_changeType), self.indexPaths]; +} + @end diff --git a/AsyncDisplayKitTests/ASTableViewThrashTests.m b/AsyncDisplayKitTests/ASTableViewThrashTests.m index ffdfa7eec8..02910a1d06 100644 --- a/AsyncDisplayKitTests/ASTableViewThrashTests.m +++ b/AsyncDisplayKitTests/ASTableViewThrashTests.m @@ -446,17 +446,22 @@ static NSInteger ASThrashUpdateCurrentSerializationVersion = 1; @implementation ASTableViewThrashTests { // The current update, which will be logged in case of a failure. ASThrashUpdate *_update; + BOOL _failed; } #pragma mark Overrides - (void)tearDown { + if (_failed && _update != nil) { + NSLog(@"Failed update %@: %@", _update, _update.logFriendlyBase64Representation); + } + _failed = NO; _update = nil; } // NOTE: Despite the documentation, this is not always called if an exception is caught. - (void)recordFailureWithDescription:(NSString *)description inFile:(NSString *)filePath atLine:(NSUInteger)lineNumber expected:(BOOL)expected { - [self logCurrentUpdateIfNeeded]; + _failed = YES; [super recordFailureWithDescription:description inFile:filePath atLine:lineNumber expected:expected]; } @@ -497,12 +502,6 @@ static NSInteger ASThrashUpdateCurrentSerializationVersion = 1; #pragma mark Helpers -- (void)logCurrentUpdateIfNeeded { - if (_update != nil) { - NSLog(@"Failed update %@: %@", _update, _update.logFriendlyBase64Representation); - } -} - - (void)applyUpdate:(ASThrashUpdate *)update toDataSource:(ASThrashDataSource *)dataSource { TableView *tableView = dataSource.tableView; @@ -535,7 +534,7 @@ static NSInteger ASThrashUpdateCurrentSerializationVersion = 1; [tableView waitUntilAllUpdatesAreCommitted]; #endif } @catch (NSException *exception) { - [self logCurrentUpdateIfNeeded]; + _failed = YES; @throw exception; } } From 9c70cec8d88a0436f17cad7927e1d06682da4dcf Mon Sep 17 00:00:00 2001 From: Adlai Holler Date: Thu, 23 Jun 2016 16:58:23 -0700 Subject: [PATCH 04/43] Improve update handling more --- AsyncDisplayKit/ASCollectionView.mm | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/AsyncDisplayKit/ASCollectionView.mm b/AsyncDisplayKit/ASCollectionView.mm index 68031f464a..63bbefc603 100644 --- a/AsyncDisplayKit/ASCollectionView.mm +++ b/AsyncDisplayKit/ASCollectionView.mm @@ -498,18 +498,21 @@ static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell"; - (void)insertSections:(NSIndexSet *)sections { ASDisplayNodeAssertMainThread(); + if (sections.count == 0) { return; } [_dataController insertSections:sections withAnimationOptions:kASCollectionViewAnimationNone]; } - (void)deleteSections:(NSIndexSet *)sections { ASDisplayNodeAssertMainThread(); + if (sections.count == 0) { return; } [_dataController deleteSections:sections withAnimationOptions:kASCollectionViewAnimationNone]; } - (void)reloadSections:(NSIndexSet *)sections { ASDisplayNodeAssertMainThread(); + if (sections.count == 0) { return; } [_dataController reloadSections:sections withAnimationOptions:kASCollectionViewAnimationNone]; } @@ -522,18 +525,21 @@ static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell"; - (void)insertItemsAtIndexPaths:(NSArray *)indexPaths { ASDisplayNodeAssertMainThread(); + if (indexPaths.count == 0) { return; } [_dataController insertRowsAtIndexPaths:indexPaths withAnimationOptions:kASCollectionViewAnimationNone]; } - (void)deleteItemsAtIndexPaths:(NSArray *)indexPaths { ASDisplayNodeAssertMainThread(); + if (indexPaths.count == 0) { return; } [_dataController deleteRowsAtIndexPaths:indexPaths withAnimationOptions:kASCollectionViewAnimationNone]; } - (void)reloadItemsAtIndexPaths:(NSArray *)indexPaths { ASDisplayNodeAssertMainThread(); + if (indexPaths.count == 0) { return; } [_dataController reloadRowsAtIndexPaths:indexPaths withAnimationOptions:kASCollectionViewAnimationNone]; } From 681876bd59673872a97c185a8f21058cdf416135 Mon Sep 17 00:00:00 2001 From: Adlai Holler Date: Thu, 23 Jun 2016 17:10:33 -0700 Subject: [PATCH 05/43] Fix more issues with data integrity --- AsyncDisplayKit/Private/_ASHierarchyChangeSet.m | 7 ++++++- AsyncDisplayKitTests/ASTableViewThrashTests.m | 4 ++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/AsyncDisplayKit/Private/_ASHierarchyChangeSet.m b/AsyncDisplayKit/Private/_ASHierarchyChangeSet.m index 26adef5cd1..0b2137fe75 100644 --- a/AsyncDisplayKit/Private/_ASHierarchyChangeSet.m +++ b/AsyncDisplayKit/Private/_ASHierarchyChangeSet.m @@ -131,6 +131,8 @@ NSString *NSStringFromASHierarchyChangeType(_ASHierarchyChangeType changeType) - (NSUInteger)newSectionForOldSection:(NSUInteger)oldSection { + ASDisplayNodeAssertNotNil(_deletedSections, @"Cannot call %@ before `markCompleted` returns.", NSStringFromSelector(_cmd)); + ASDisplayNodeAssertNotNil(_insertedSections, @"Cannot call %@ before `markCompleted` returns.", NSStringFromSelector(_cmd)); [self _ensureCompleted]; if ([_deletedSections containsIndex:oldSection]) { return NSNotFound; @@ -225,6 +227,10 @@ NSString *NSStringFromASHierarchyChangeType(_ASHierarchyChangeType changeType) { @autoreleasepool { + // Give these their "pre-reloads" values. Once we add in the reloads we'll re-process them. + _deletedSections = [_ASHierarchySectionChange allIndexesInSectionChanges:_deleteSectionChanges]; + _insertedSections = [_ASHierarchySectionChange allIndexesInSectionChanges:_insertSectionChanges]; + // Split reloaded section indexes into deletes and inserts // Delete the old section, insert the new section it corresponds to. for (_ASHierarchySectionChange *change in _reloadSectionChanges) { @@ -245,7 +251,6 @@ NSString *NSStringFromASHierarchyChangeType(_ASHierarchyChangeType changeType) [_ASHierarchySectionChange sortAndCoalesceChanges:_deleteSectionChanges]; [_ASHierarchySectionChange sortAndCoalesceChanges:_insertSectionChanges]; - [_ASHierarchySectionChange sortAndCoalesceChanges:_reloadSectionChanges]; _deletedSections = [_ASHierarchySectionChange allIndexesInSectionChanges:_deleteSectionChanges]; _insertedSections = [_ASHierarchySectionChange allIndexesInSectionChanges:_insertSectionChanges]; diff --git a/AsyncDisplayKitTests/ASTableViewThrashTests.m b/AsyncDisplayKitTests/ASTableViewThrashTests.m index 02910a1d06..92b3cc2f2c 100644 --- a/AsyncDisplayKitTests/ASTableViewThrashTests.m +++ b/AsyncDisplayKitTests/ASTableViewThrashTests.m @@ -146,7 +146,7 @@ static volatile int32_t ASThrashTestSectionNextID = 1; } - (NSString *)description { - return [NSString stringWithFormat:@"
", (unsigned long)_sectionID, (unsigned long)self.items.count]; + return [NSString stringWithFormat:@"
", (unsigned long)_sectionID, (unsigned long)self.items.count, ASThrashArrayDescription(self.items)]; } - (id)copyWithZone:(NSZone *)zone { @@ -554,7 +554,7 @@ static NSInteger ASThrashUpdateCurrentSerializationVersion = 1; XCTAssertEqual([tableView rectForRowAtIndexPath:indexPath].size.height, item.rowHeight); #else ASThrashTestNode *node = (ASThrashTestNode *)[tableView nodeForRowAtIndexPath:indexPath]; - XCTAssertEqual(node.item, item); + XCTAssertEqualObjects(node.item, item, @"Wrong node at index path %@", indexPath); #endif } } From d8d2524b89b07bb683dd0b968136b28f611550b7 Mon Sep 17 00:00:00 2001 From: Adlai Holler Date: Thu, 23 Jun 2016 17:28:22 -0700 Subject: [PATCH 06/43] One more critical update integrity fix --- AsyncDisplayKit/Details/NSIndexSet+ASHelpers.h | 4 ++-- AsyncDisplayKit/Details/NSIndexSet+ASHelpers.m | 4 ++-- AsyncDisplayKit/Private/_ASHierarchyChangeSet.m | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/AsyncDisplayKit/Details/NSIndexSet+ASHelpers.h b/AsyncDisplayKit/Details/NSIndexSet+ASHelpers.h index 54e9ac0126..179e685639 100644 --- a/AsyncDisplayKit/Details/NSIndexSet+ASHelpers.h +++ b/AsyncDisplayKit/Details/NSIndexSet+ASHelpers.h @@ -17,8 +17,8 @@ /// Returns all the item indexes from the given index paths that are in the given section. + (NSIndexSet *)as_indexSetFromIndexPaths:(NSArray *)indexPaths inSection:(NSUInteger)section; -/// If you've got an old index, and you insert items using this index set, this returns the new index. -- (NSUInteger)as_indexByInsertingItemsBelowIndex:(NSUInteger)index; +/// If you've got an old index, and you insert items using this index set, this returns the change to get to the new index. +- (NSUInteger)as_indexChangeByInsertingItemsBelowIndex:(NSUInteger)index; - (NSString *)as_smallDescription; diff --git a/AsyncDisplayKit/Details/NSIndexSet+ASHelpers.m b/AsyncDisplayKit/Details/NSIndexSet+ASHelpers.m index feac7ec8d0..0837ad0eaa 100644 --- a/AsyncDisplayKit/Details/NSIndexSet+ASHelpers.m +++ b/AsyncDisplayKit/Details/NSIndexSet+ASHelpers.m @@ -46,7 +46,7 @@ return result; } -- (NSUInteger)as_indexByInsertingItemsBelowIndex:(NSUInteger)index +- (NSUInteger)as_indexChangeByInsertingItemsBelowIndex:(NSUInteger)index { __block NSUInteger newIndex = index; [self enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL * _Nonnull stop) { @@ -56,7 +56,7 @@ *stop = YES; } }]; - return newIndex; + return newIndex - index; } - (NSString *)as_smallDescription diff --git a/AsyncDisplayKit/Private/_ASHierarchyChangeSet.m b/AsyncDisplayKit/Private/_ASHierarchyChangeSet.m index 0b2137fe75..e7218f6d23 100644 --- a/AsyncDisplayKit/Private/_ASHierarchyChangeSet.m +++ b/AsyncDisplayKit/Private/_ASHierarchyChangeSet.m @@ -139,7 +139,7 @@ NSString *NSStringFromASHierarchyChangeType(_ASHierarchyChangeType changeType) } NSUInteger newIndex = oldSection - [_deletedSections countOfIndexesInRange:NSMakeRange(0, oldSection)]; - newIndex = [_insertedSections as_indexByInsertingItemsBelowIndex:newIndex]; + newIndex += [_insertedSections as_indexChangeByInsertingItemsBelowIndex:newIndex]; return newIndex; } @@ -276,7 +276,7 @@ NSString *NSStringFromASHierarchyChangeType(_ASHierarchyChangeType changeType) item -= [indicesDeletedInSection countOfIndexesInRange:NSMakeRange(0, item)]; // Update row number based on insertions that are above the current row in the future section NSIndexSet *indicesInsertedInSection = insertedIndexPathsMap[@(section)]; - item = [indicesInsertedInSection as_indexByInsertingItemsBelowIndex:item]; + item += [indicesInsertedInSection as_indexChangeByInsertingItemsBelowIndex:item]; //TODO: reuse the old indexPath object if section and row aren't changed NSIndexPath *newIndexPath = [NSIndexPath indexPathForItem:item inSection:section]; From 5d72f2f2ccefc2d2aec9a0e2f08fe189aad0e6c2 Mon Sep 17 00:00:00 2001 From: Adlai Holler Date: Thu, 23 Jun 2016 17:30:18 -0700 Subject: [PATCH 07/43] Enable the thrash testing --- AsyncDisplayKitTests/ASTableViewThrashTests.m | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/AsyncDisplayKitTests/ASTableViewThrashTests.m b/AsyncDisplayKitTests/ASTableViewThrashTests.m index 92b3cc2f2c..62ddffdd90 100644 --- a/AsyncDisplayKitTests/ASTableViewThrashTests.m +++ b/AsyncDisplayKitTests/ASTableViewThrashTests.m @@ -20,8 +20,8 @@ #define TableView ASTableView #endif -#define kInitialSectionCount 20 -#define kInitialItemCount 20 +#define kInitialSectionCount 10 +#define kInitialItemCount 10 #define kMinimumItemCount 5 #define kMinimumSectionCount 3 #define kFickleness 0.1 @@ -488,7 +488,7 @@ static NSInteger ASThrashUpdateCurrentSerializationVersion = 1; [self verifyDataSource:ds]; } -- (void)DISABLED_testThrashingWildly { +- (void)testThrashingWildly { for (NSInteger i = 0; i < kThrashingIterationCount; i++) { [self setUp]; ASThrashDataSource *ds = [[ASThrashDataSource alloc] initWithData:[ASThrashTestSection sectionsWithCount:kInitialSectionCount]]; From 84e8b2686c84edd98f53f4d15fe6b819bb840fc9 Mon Sep 17 00:00:00 2001 From: Adlai Holler Date: Fri, 24 Jun 2016 13:03:51 -0700 Subject: [PATCH 08/43] [ASDataController] Combine isolated reloads into a batch --- AsyncDisplayKit/Details/ASChangeSetDataController.m | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/AsyncDisplayKit/Details/ASChangeSetDataController.m b/AsyncDisplayKit/Details/ASChangeSetDataController.m index 7802a6c1d5..f6615d1bdb 100644 --- a/AsyncDisplayKit/Details/ASChangeSetDataController.m +++ b/AsyncDisplayKit/Details/ASChangeSetDataController.m @@ -109,8 +109,10 @@ if ([self batchUpdating]) { [_changeSet reloadSections:sections animationOptions:animationOptions]; } else { + [self beginUpdates]; [super deleteSections:sections withAnimationOptions:animationOptions]; [super insertSections:sections withAnimationOptions:animationOptions]; + [self endUpdates]; } } @@ -153,8 +155,10 @@ if ([self batchUpdating]) { [_changeSet reloadItems:indexPaths animationOptions:animationOptions]; } else { + [self beginUpdates]; [super deleteRowsAtIndexPaths:indexPaths withAnimationOptions:animationOptions]; [super insertRowsAtIndexPaths:indexPaths withAnimationOptions:animationOptions]; + [self endUpdates]; } } From 304f8f6cb1e06bcb9b720697d66d87792c825551 Mon Sep 17 00:00:00 2001 From: Adlai Holler Date: Fri, 24 Jun 2016 13:17:00 -0700 Subject: [PATCH 09/43] [ASHierarchyChangeSet] Clean up and add documentation --- .../Private/_ASHierarchyChangeSet.h | 4 ++-- .../Private/_ASHierarchyChangeSet.m | 21 ++++++++----------- 2 files changed, 11 insertions(+), 14 deletions(-) diff --git a/AsyncDisplayKit/Private/_ASHierarchyChangeSet.h b/AsyncDisplayKit/Private/_ASHierarchyChangeSet.h index 9387a91d56..f514be705b 100644 --- a/AsyncDisplayKit/Private/_ASHierarchyChangeSet.h +++ b/AsyncDisplayKit/Private/_ASHierarchyChangeSet.h @@ -87,8 +87,8 @@ NSString *NSStringFromASHierarchyChangeType(_ASHierarchyChangeType changeType); - Inserted sections, ascending order - Inserted items, ascending order */ -- (NSArray <_ASHierarchySectionChange *> *)sectionChangesOfType:(_ASHierarchyChangeType)changeType; -- (NSArray <_ASHierarchyItemChange *> *)itemChangesOfType:(_ASHierarchyChangeType)changeType; +- (nullable NSArray <_ASHierarchySectionChange *> *)sectionChangesOfType:(_ASHierarchyChangeType)changeType; +- (nullable NSArray <_ASHierarchyItemChange *> *)itemChangesOfType:(_ASHierarchyChangeType)changeType; /// Returns all item indexes affected by changes of the given type in the given section. - (NSIndexSet *)indexesForItemChangesOfType:(_ASHierarchyChangeType)changeType inSection:(NSUInteger)section; diff --git a/AsyncDisplayKit/Private/_ASHierarchyChangeSet.m b/AsyncDisplayKit/Private/_ASHierarchyChangeSet.m index e7218f6d23..9075f36878 100644 --- a/AsyncDisplayKit/Private/_ASHierarchyChangeSet.m +++ b/AsyncDisplayKit/Private/_ASHierarchyChangeSet.m @@ -227,16 +227,16 @@ NSString *NSStringFromASHierarchyChangeType(_ASHierarchyChangeType changeType) { @autoreleasepool { + // Split reloaded sections into [delete(oldIndex), insert(newIndex)] + // Give these their "pre-reloads" values. Once we add in the reloads we'll re-process them. _deletedSections = [_ASHierarchySectionChange allIndexesInSectionChanges:_deleteSectionChanges]; _insertedSections = [_ASHierarchySectionChange allIndexesInSectionChanges:_insertSectionChanges]; - // Split reloaded section indexes into deletes and inserts - // Delete the old section, insert the new section it corresponds to. for (_ASHierarchySectionChange *change in _reloadSectionChanges) { NSIndexSet *newSections = [change.indexSet as_indexesByMapping:^(NSUInteger idx) { NSUInteger newSec = [self newSectionForOldSection:idx]; - NSAssert(newSec != NSNotFound, nil); + NSAssert(newSec != NSNotFound, @"Request to reload deleted section %lu", (unsigned long)idx); return newSec; }]; @@ -254,13 +254,14 @@ NSString *NSStringFromASHierarchyChangeType(_ASHierarchyChangeType changeType) _deletedSections = [_ASHierarchySectionChange allIndexesInSectionChanges:_deleteSectionChanges]; _insertedSections = [_ASHierarchySectionChange allIndexesInSectionChanges:_insertSectionChanges]; - // reload items changes need to be adjusted so that we access the correct indexPaths in the datasource + // Split reloaded items into [delete(oldIndexPath), insert(newIndexPath)] + NSDictionary *insertedIndexPathsMap = [_ASHierarchyItemChange sectionToIndexSetMapFromChanges:_insertItemChanges ofType:_ASHierarchyChangeTypeInsert]; NSDictionary *deletedIndexPathsMap = [_ASHierarchyItemChange sectionToIndexSetMapFromChanges:_deleteItemChanges ofType:_ASHierarchyChangeTypeDelete]; for (_ASHierarchyItemChange *change in _reloadItemChanges) { NSAssert(change.changeType == _ASHierarchyChangeTypeReload, @"It must be a reload change to be in here"); - NSMutableArray *newIndexPaths = [NSMutableArray array]; + NSMutableArray *newIndexPaths = [NSMutableArray arrayWithCapacity:change.indexPaths.count]; // Every indexPaths in the change need to update its section and/or row // depending on all the deletions and insertions @@ -278,7 +279,6 @@ NSString *NSStringFromASHierarchyChangeType(_ASHierarchyChangeType changeType) NSIndexSet *indicesInsertedInSection = insertedIndexPathsMap[@(section)]; item += [indicesInsertedInSection as_indexChangeByInsertingItemsBelowIndex:item]; - //TODO: reuse the old indexPath object if section and row aren't changed NSIndexPath *newIndexPath = [NSIndexPath indexPathForItem:item inSection:section]; [newIndexPaths addObject:newIndexPath]; } @@ -291,7 +291,7 @@ NSString *NSStringFromASHierarchyChangeType(_ASHierarchyChangeType changeType) _ASHierarchyItemChange *insertItemChangeFromReloadChange = [[_ASHierarchyItemChange alloc] initWithChangeType:_ASHierarchyChangeTypeInsert indexPaths:newIndexPaths animationOptions:change.animationOptions presorted:NO]; [_insertItemChanges addObject:insertItemChangeFromReloadChange]; } - [_reloadItemChanges removeAllObjects]; + _reloadItemChanges = nil; // Ignore item deletes in reloaded/deleted sections. [_ASHierarchyItemChange sortAndCoalesceChanges:_deleteItemChanges ignoringChangesInSections:_deletedSections]; @@ -436,7 +436,7 @@ NSString *NSStringFromASHierarchyChangeType(_ASHierarchyChangeType changeType) return sectionToIndexSetMap; } -+ (void)sortAndCoalesceChanges:(NSMutableArray *)changes ignoringChangesInSections:(NSIndexSet *)sections ++ (void)sortAndCoalesceChanges:(NSMutableArray *)changes ignoringChangesInSections:(NSIndexSet *)ignoredSections { if (changes.count < 1) { return; @@ -450,12 +450,9 @@ NSString *NSStringFromASHierarchyChangeType(_ASHierarchyChangeType changeType) // All changed index paths, sorted NSMutableArray *allIndexPaths = [NSMutableArray new]; - NSPredicate *indexPathInValidSection = [NSPredicate predicateWithBlock:^BOOL(NSIndexPath *indexPath, __unused NSDictionary *_) { - return ![sections containsIndex:indexPath.section]; - }]; for (_ASHierarchyItemChange *change in changes) { for (NSIndexPath *indexPath in change.indexPaths) { - if ([indexPathInValidSection evaluateWithObject:indexPath]) { + if (![ignoredSections containsIndex:indexPath.section]) { animationOptions[indexPath] = @(change.animationOptions); [allIndexPaths addObject:indexPath]; } From 27dc52c0c506e689d988373e8379bccd294cf38c Mon Sep 17 00:00:00 2001 From: Adlai Holler Date: Fri, 24 Jun 2016 13:20:06 -0700 Subject: [PATCH 10/43] [ASHierarchyChangeSet] Document reload-splitting behavior --- AsyncDisplayKit/Private/_ASHierarchyChangeSet.h | 1 + 1 file changed, 1 insertion(+) diff --git a/AsyncDisplayKit/Private/_ASHierarchyChangeSet.h b/AsyncDisplayKit/Private/_ASHierarchyChangeSet.h index f514be705b..782607fd0c 100644 --- a/AsyncDisplayKit/Private/_ASHierarchyChangeSet.h +++ b/AsyncDisplayKit/Private/_ASHierarchyChangeSet.h @@ -71,6 +71,7 @@ NSString *NSStringFromASHierarchyChangeType(_ASHierarchyChangeType changeType); @property (nonatomic, readonly) BOOL completed; /// Call this once the change set has been constructed to prevent future modifications to the changeset. Calling this more than once is a programmer error. +/// NOTE: Calling this method will cause the changeset to convert all reloads into delete/insert pairs. - (void)markCompleted; /** From 0a525a3c16f3dca6245f2b9be4677f85f56ff8d7 Mon Sep 17 00:00:00 2001 From: Adlai Holler Date: Fri, 24 Jun 2016 13:52:16 -0700 Subject: [PATCH 11/43] [ASFlowLayoutController] Fix enumeration bug in ASFlowLayoutController --- AsyncDisplayKit/Details/ASFlowLayoutController.mm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/AsyncDisplayKit/Details/ASFlowLayoutController.mm b/AsyncDisplayKit/Details/ASFlowLayoutController.mm index cb754bb9bf..ffd553ba96 100644 --- a/AsyncDisplayKit/Details/ASFlowLayoutController.mm +++ b/AsyncDisplayKit/Details/ASFlowLayoutController.mm @@ -92,12 +92,12 @@ currPath.row++; // Once we reach the end of the section, advance to the next one. Keep advancing if the next section is zero-sized. - while (currPath.row >= [(NSArray *)completedNodes[currPath.section] count] && currPath.section < completedNodes.count - 1) { + while (currPath.row >= [(NSArray *)completedNodes[currPath.section] count] && currPath.section < endPath.section) { currPath.row = 0; currPath.section++; - ASDisplayNodeAssert(currPath.section <= endPath.section, @"currPath should never reach a further section than endPath"); } } + ASDisplayNodeAssert(currPath.section <= endPath.section, @"currPath should never reach a further section than endPath"); [indexPathSet addObject:[NSIndexPath indexPathWithASIndexPath:endPath]]; From 211dcdf0e8f827347c3fceecd019067728b8ad6d Mon Sep 17 00:00:00 2001 From: Adlai Holler Date: Fri, 24 Jun 2016 13:56:08 -0700 Subject: [PATCH 12/43] [_ASHierarchyChangeSet] Remove unused new method --- .../Private/_ASHierarchyChangeSet.h | 8 ------- .../Private/_ASHierarchyChangeSet.m | 24 ------------------- 2 files changed, 32 deletions(-) diff --git a/AsyncDisplayKit/Private/_ASHierarchyChangeSet.h b/AsyncDisplayKit/Private/_ASHierarchyChangeSet.h index 782607fd0c..755d82004d 100644 --- a/AsyncDisplayKit/Private/_ASHierarchyChangeSet.h +++ b/AsyncDisplayKit/Private/_ASHierarchyChangeSet.h @@ -60,14 +60,6 @@ NSString *NSStringFromASHierarchyChangeType(_ASHierarchyChangeType changeType); */ - (NSUInteger)newSectionForOldSection:(NSUInteger)oldSection; -/** - Get the index path after the update for the item at the given index path before the update. - - @precondition The change set must be completed. - @returns The new index path, or nil if the given item (or its section) was deleted. - */ -- (nullable NSIndexPath *)newIndexPathForOldIndexPath:(NSIndexPath *)indexPath; - @property (nonatomic, readonly) BOOL completed; /// Call this once the change set has been constructed to prevent future modifications to the changeset. Calling this more than once is a programmer error. diff --git a/AsyncDisplayKit/Private/_ASHierarchyChangeSet.m b/AsyncDisplayKit/Private/_ASHierarchyChangeSet.m index 9075f36878..d1b54438a0 100644 --- a/AsyncDisplayKit/Private/_ASHierarchyChangeSet.m +++ b/AsyncDisplayKit/Private/_ASHierarchyChangeSet.m @@ -143,30 +143,6 @@ NSString *NSStringFromASHierarchyChangeType(_ASHierarchyChangeType changeType) return newIndex; } -- (nullable NSIndexPath *)newIndexPathForOldIndexPath:(NSIndexPath *)indexPath -{ - [self _ensureCompleted]; - // If section was deleted, nil - NSUInteger oldSection = indexPath.section; - NSUInteger newSection = [self newSectionForOldSection:oldSection]; - if (newSection == NSNotFound) { - return nil; - } - - NSUInteger newItem = indexPath.item; - NSIndexSet *deletedItemsInOldSection = [self indexesForItemChangesOfType:_ASHierarchyChangeTypeDelete inSection:oldSection]; - newItem -= [deletedItemsInOldSection countOfIndexesInRange:NSMakeRange(0, newItem)]; - - for (_ASHierarchyItemChange *change in _deleteItemChanges) { - // If item was deleted, nil - if ([change.indexPaths containsObject:indexPath]) { - return nil; - } - } - - return [NSIndexPath indexPathForItem:newItem inSection:newSection]; -} - - (void)deleteItems:(NSArray *)indexPaths animationOptions:(ASDataControllerAnimationOptions)options { [self _ensureNotCompleted]; From 0a354f8f4eaf6ddfb44b891a4d8f102453c27ed2 Mon Sep 17 00:00:00 2001 From: Adlai Holler Date: Fri, 24 Jun 2016 15:48:23 -0700 Subject: [PATCH 13/43] [ASDataController] Remove implementation for unused hooks --- AsyncDisplayKit/Details/ASDataController.mm | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/AsyncDisplayKit/Details/ASDataController.mm b/AsyncDisplayKit/Details/ASDataController.mm index 74869de0d7..163b812e10 100644 --- a/AsyncDisplayKit/Details/ASDataController.mm +++ b/AsyncDisplayKit/Details/ASDataController.mm @@ -725,16 +725,6 @@ static void *kASSizingQueueContext = &kASSizingQueueContext; // Optional template hook for subclasses (See ASDataController+Subclasses.h) } -- (void)prepareForReloadSections:(NSIndexSet *)sections -{ - // Optional template hook for subclasses (See ASDataController+Subclasses.h) -} - -- (void)willReloadSections:(NSIndexSet *)sections -{ - // Optional template hook for subclasses (See ASDataController+Subclasses.h) -} - - (void)willMoveSection:(NSInteger)section toSection:(NSInteger)newSection { // Optional template hook for subclasses (See ASDataController+Subclasses.h) From f71e207e0afc7708a1da01d71191deb4466e5133 Mon Sep 17 00:00:00 2001 From: Hannah Troisi Date: Sun, 26 Jun 2016 17:08:35 -0700 Subject: [PATCH 14/43] Remove old website files from master branch (#1817) - new website files are in gh-pages branch (and have been for awhile) --- docs/CNAME | 2 - docs/LICENSE.md | 420 ------------------------ docs/README.md | 9 - docs/_config.yml | 13 - docs/_includes/footer.html | 18 - docs/_includes/head.html | 24 -- docs/_includes/header.html | 25 -- docs/_layouts/default.html | 20 -- docs/_layouts/docs.html | 27 -- docs/_layouts/page.html | 16 - docs/_layouts/post.html | 15 - docs/_sass/_base.scss | 205 ------------ docs/_sass/_layout.scss | 265 --------------- docs/_sass/_syntax-highlighting.scss | 76 ----- docs/assets/guide/1-shuffle-crop.png | Bin 1016 -> 0 bytes docs/assets/guide/1-shuffle.png | Bin 19288 -> 0 bytes docs/assets/logo-square.png | Bin 66422 -> 0 bytes docs/assets/logo.png | Bin 105684 -> 0 bytes docs/assets/node-view-layer.png | Bin 12961 -> 0 bytes docs/build.sh | 33 -- docs/css/main.scss | 49 --- docs/guide/1-introduction.md | 150 --------- docs/guide/2-custom-nodes.md | 211 ------------ docs/guide/3-asynchronous-display.md | 102 ------ docs/guide/4-making-the-most-of-asdk.md | 139 -------- docs/guide/5-under-the-hood.md | 89 ----- docs/index.md | 86 ----- 27 files changed, 1994 deletions(-) delete mode 100644 docs/CNAME delete mode 100644 docs/LICENSE.md delete mode 100644 docs/README.md delete mode 100644 docs/_config.yml delete mode 100644 docs/_includes/footer.html delete mode 100644 docs/_includes/head.html delete mode 100644 docs/_includes/header.html delete mode 100644 docs/_layouts/default.html delete mode 100644 docs/_layouts/docs.html delete mode 100644 docs/_layouts/page.html delete mode 100644 docs/_layouts/post.html delete mode 100644 docs/_sass/_base.scss delete mode 100644 docs/_sass/_layout.scss delete mode 100644 docs/_sass/_syntax-highlighting.scss delete mode 100644 docs/assets/guide/1-shuffle-crop.png delete mode 100644 docs/assets/guide/1-shuffle.png delete mode 100755 docs/assets/logo-square.png delete mode 100755 docs/assets/logo.png delete mode 100755 docs/assets/node-view-layer.png delete mode 100755 docs/build.sh delete mode 100755 docs/css/main.scss delete mode 100644 docs/guide/1-introduction.md delete mode 100644 docs/guide/2-custom-nodes.md delete mode 100644 docs/guide/3-asynchronous-display.md delete mode 100644 docs/guide/4-making-the-most-of-asdk.md delete mode 100644 docs/guide/5-under-the-hood.md delete mode 100644 docs/index.md diff --git a/docs/CNAME b/docs/CNAME deleted file mode 100644 index a295f461e5..0000000000 --- a/docs/CNAME +++ /dev/null @@ -1,2 +0,0 @@ -asyncdisplaykit.org - diff --git a/docs/LICENSE.md b/docs/LICENSE.md deleted file mode 100644 index 4bb498ec63..0000000000 --- a/docs/LICENSE.md +++ /dev/null @@ -1,420 +0,0 @@ ---- -layout: page -title: License -permalink: /license/ ---- - -AsyncDisplayKit is free software under the BSD -license. - -Code examples and sample -projects are licensed as follows: - - This file provided by Facebook is for non-commercial testing and evaluation - purposes only. Facebook reserves all rights not expressly granted. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -All other AsyncDisplayKit documentation is licensed CC-BY-4.0. - - Attribution 4.0 International - - ======================================================================= - - Creative Commons Corporation ("Creative Commons") is not a law firm and - does not provide legal services or legal advice. Distribution of - Creative Commons public licenses does not create a lawyer-client or - other relationship. Creative Commons makes its licenses and related - information available on an "as-is" basis. Creative Commons gives no - warranties regarding its licenses, any material licensed under their - terms and conditions, or any related information. Creative Commons - disclaims all liability for damages resulting from their use to the - fullest extent possible. - - Using Creative Commons Public Licenses - - Creative Commons public licenses provide a standard set of terms and - conditions that creators and other rights holders may use to share - original works of authorship and other material subject to copyright - and certain other rights specified in the public license below. The - following considerations are for informational purposes only, are not - exhaustive, and do not form part of our licenses. - - Considerations for licensors: Our public licenses are - intended for use by those authorized to give the public - permission to use material in ways otherwise restricted by - copyright and certain other rights. Our licenses are - irrevocable. Licensors should read and understand the terms - and conditions of the license they choose before applying it. - Licensors should also secure all rights necessary before - applying our licenses so that the public can reuse the - material as expected. Licensors should clearly mark any - material not subject to the license. This includes other CC- - licensed material, or material used under an exception or - limitation to copyright. More considerations for licensors: - wiki.creativecommons.org/Considerations_for_licensors - - Considerations for the public: By using one of our public - licenses, a licensor grants the public permission to use the - licensed material under specified terms and conditions. If - the licensor's permission is not necessary for any reason--for - example, because of any applicable exception or limitation to - copyright--then that use is not regulated by the license. Our - licenses grant only permissions under copyright and certain - other rights that a licensor has authority to grant. Use of - the licensed material may still be restricted for other - reasons, including because others have copyright or other - rights in the material. A licensor may make special requests, - such as asking that all changes be marked or described. - Although not required by our licenses, you are encouraged to - respect those requests where reasonable. More_considerations - for the public: - wiki.creativecommons.org/Considerations_for_licensees - - ======================================================================= - - Creative Commons Attribution 4.0 International Public License - - By exercising the Licensed Rights (defined below), You accept and agree - to be bound by the terms and conditions of this Creative Commons - Attribution 4.0 International Public License ("Public License"). To the - extent this Public License may be interpreted as a contract, You are - granted the Licensed Rights in consideration of Your acceptance of - these terms and conditions, and the Licensor grants You such rights in - consideration of benefits the Licensor receives from making the - Licensed Material available under these terms and conditions. - - - Section 1 -- Definitions. - - a. Adapted Material means material subject to Copyright and Similar - Rights that is derived from or based upon the Licensed Material - and in which the Licensed Material is translated, altered, - arranged, transformed, or otherwise modified in a manner requiring - permission under the Copyright and Similar Rights held by the - Licensor. For purposes of this Public License, where the Licensed - Material is a musical work, performance, or sound recording, - Adapted Material is always produced where the Licensed Material is - synched in timed relation with a moving image. - - b. Adapter's License means the license You apply to Your Copyright - and Similar Rights in Your contributions to Adapted Material in - accordance with the terms and conditions of this Public License. - - c. Copyright and Similar Rights means copyright and/or similar rights - closely related to copyright including, without limitation, - performance, broadcast, sound recording, and Sui Generis Database - Rights, without regard to how the rights are labeled or - categorized. For purposes of this Public License, the rights - specified in Section 2(b)(1)-(2) are not Copyright and Similar - Rights. - - d. Effective Technological Measures means those measures that, in the - absence of proper authority, may not be circumvented under laws - fulfilling obligations under Article 11 of the WIPO Copyright - Treaty adopted on December 20, 1996, and/or similar international - agreements. - - e. Exceptions and Limitations means fair use, fair dealing, and/or - any other exception or limitation to Copyright and Similar Rights - that applies to Your use of the Licensed Material. - - f. Licensed Material means the artistic or literary work, database, - or other material to which the Licensor applied this Public - License. - - g. Licensed Rights means the rights granted to You subject to the - terms and conditions of this Public License, which are limited to - all Copyright and Similar Rights that apply to Your use of the - Licensed Material and that the Licensor has authority to license. - - h. Licensor means the individual(s) or entity(ies) granting rights - under this Public License. - - i. Share means to provide material to the public by any means or - process that requires permission under the Licensed Rights, such - as reproduction, public display, public performance, distribution, - dissemination, communication, or importation, and to make material - available to the public including in ways that members of the - public may access the material from a place and at a time - individually chosen by them. - - j. Sui Generis Database Rights means rights other than copyright - resulting from Directive 96/9/EC of the European Parliament and of - the Council of 11 March 1996 on the legal protection of databases, - as amended and/or succeeded, as well as other essentially - equivalent rights anywhere in the world. - - k. You means the individual or entity exercising the Licensed Rights - under this Public License. Your has a corresponding meaning. - - - Section 2 -- Scope. - - a. License grant. - - 1. Subject to the terms and conditions of this Public License, - the Licensor hereby grants You a worldwide, royalty-free, - non-sublicensable, non-exclusive, irrevocable license to - exercise the Licensed Rights in the Licensed Material to: - - a. reproduce and Share the Licensed Material, in whole or - in part; and - - b. produce, reproduce, and Share Adapted Material. - - 2. Exceptions and Limitations. For the avoidance of doubt, where - Exceptions and Limitations apply to Your use, this Public - License does not apply, and You do not need to comply with - its terms and conditions. - - 3. Term. The term of this Public License is specified in Section - 6(a). - - 4. Media and formats; technical modifications allowed. The - Licensor authorizes You to exercise the Licensed Rights in - all media and formats whether now known or hereafter created, - and to make technical modifications necessary to do so. The - Licensor waives and/or agrees not to assert any right or - authority to forbid You from making technical modifications - necessary to exercise the Licensed Rights, including - technical modifications necessary to circumvent Effective - Technological Measures. For purposes of this Public License, - simply making modifications authorized by this Section 2(a) - (4) never produces Adapted Material. - - 5. Downstream recipients. - - a. Offer from the Licensor -- Licensed Material. Every - recipient of the Licensed Material automatically - receives an offer from the Licensor to exercise the - Licensed Rights under the terms and conditions of this - Public License. - - b. No downstream restrictions. You may not offer or impose - any additional or different terms or conditions on, or - apply any Effective Technological Measures to, the - Licensed Material if doing so restricts exercise of the - Licensed Rights by any recipient of the Licensed - Material. - - 6. No endorsement. Nothing in this Public License constitutes or - may be construed as permission to assert or imply that You - are, or that Your use of the Licensed Material is, connected - with, or sponsored, endorsed, or granted official status by, - the Licensor or others designated to receive attribution as - provided in Section 3(a)(1)(A)(i). - - b. Other rights. - - 1. Moral rights, such as the right of integrity, are not - licensed under this Public License, nor are publicity, - privacy, and/or other similar personality rights; however, to - the extent possible, the Licensor waives and/or agrees not to - assert any such rights held by the Licensor to the limited - extent necessary to allow You to exercise the Licensed - Rights, but not otherwise. - - 2. Patent and trademark rights are not licensed under this - Public License. - - 3. To the extent possible, the Licensor waives any right to - collect royalties from You for the exercise of the Licensed - Rights, whether directly or through a collecting society - under any voluntary or waivable statutory or compulsory - licensing scheme. In all other cases the Licensor expressly - reserves any right to collect such royalties. - - - Section 3 -- License Conditions. - - Your exercise of the Licensed Rights is expressly made subject to the - following conditions. - - a. Attribution. - - 1. If You Share the Licensed Material (including in modified - form), You must: - - a. retain the following if it is supplied by the Licensor - with the Licensed Material: - - i. identification of the creator(s) of the Licensed - Material and any others designated to receive - attribution, in any reasonable manner requested by - the Licensor (including by pseudonym if - designated); - - ii. a copyright notice; - - iii. a notice that refers to this Public License; - - iv. a notice that refers to the disclaimer of - warranties; - - v. a URI or hyperlink to the Licensed Material to the - extent reasonably practicable; - - b. indicate if You modified the Licensed Material and - retain an indication of any previous modifications; and - - c. indicate the Licensed Material is licensed under this - Public License, and include the text of, or the URI or - hyperlink to, this Public License. - - 2. You may satisfy the conditions in Section 3(a)(1) in any - reasonable manner based on the medium, means, and context in - which You Share the Licensed Material. For example, it may be - reasonable to satisfy the conditions by providing a URI or - hyperlink to a resource that includes the required - information. - - 3. If requested by the Licensor, You must remove any of the - information required by Section 3(a)(1)(A) to the extent - reasonably practicable. - - 4. If You Share Adapted Material You produce, the Adapter's - License You apply must not prevent recipients of the Adapted - Material from complying with this Public License. - - - Section 4 -- Sui Generis Database Rights. - - Where the Licensed Rights include Sui Generis Database Rights that - apply to Your use of the Licensed Material: - - a. for the avoidance of doubt, Section 2(a)(1) grants You the right - to extract, reuse, reproduce, and Share all or a substantial - portion of the contents of the database; - - b. if You include all or a substantial portion of the database - contents in a database in which You have Sui Generis Database - Rights, then the database in which You have Sui Generis Database - Rights (but not its individual contents) is Adapted Material; and - - c. You must comply with the conditions in Section 3(a) if You Share - all or a substantial portion of the contents of the database. - - For the avoidance of doubt, this Section 4 supplements and does not - replace Your obligations under this Public License where the Licensed - Rights include other Copyright and Similar Rights. - - - Section 5 -- Disclaimer of Warranties and Limitation of Liability. - - a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE - EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS - AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF - ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS, - IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION, - WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR - PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS, - ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT - KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT - ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU. - - b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE - TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION, - NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT, - INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES, - COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR - USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN - ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR - DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR - IN PART, THIS LIMITATION MAY NOT APPLY TO YOU. - - c. The disclaimer of warranties and limitation of liability provided - above shall be interpreted in a manner that, to the extent - possible, most closely approximates an absolute disclaimer and - waiver of all liability. - - - Section 6 -- Term and Termination. - - a. This Public License applies for the term of the Copyright and - Similar Rights licensed here. However, if You fail to comply with - this Public License, then Your rights under this Public License - terminate automatically. - - b. Where Your right to use the Licensed Material has terminated under - Section 6(a), it reinstates: - - 1. automatically as of the date the violation is cured, provided - it is cured within 30 days of Your discovery of the - violation; or - - 2. upon express reinstatement by the Licensor. - - For the avoidance of doubt, this Section 6(b) does not affect any - right the Licensor may have to seek remedies for Your violations - of this Public License. - - c. For the avoidance of doubt, the Licensor may also offer the - Licensed Material under separate terms or conditions or stop - distributing the Licensed Material at any time; however, doing so - will not terminate this Public License. - - d. Sections 1, 5, 6, 7, and 8 survive termination of this Public - License. - - - Section 7 -- Other Terms and Conditions. - - a. The Licensor shall not be bound by any additional or different - terms or conditions communicated by You unless expressly agreed. - - b. Any arrangements, understandings, or agreements regarding the - Licensed Material not stated herein are separate from and - independent of the terms and conditions of this Public License. - - - Section 8 -- Interpretation. - - a. For the avoidance of doubt, this Public License does not, and - shall not be interpreted to, reduce, limit, restrict, or impose - conditions on any use of the Licensed Material that could lawfully - be made without permission under this Public License. - - b. To the extent possible, if any provision of this Public License is - deemed unenforceable, it shall be automatically reformed to the - minimum extent necessary to make it enforceable. If the provision - cannot be reformed, it shall be severed from this Public License - without affecting the enforceability of the remaining terms and - conditions. - - c. No term or condition of this Public License will be waived and no - failure to comply consented to unless expressly agreed to by the - Licensor. - - d. Nothing in this Public License constitutes or may be interpreted - as a limitation upon, or waiver of, any privileges and immunities - that apply to the Licensor or You, including from the legal - processes of any jurisdiction or authority. - - - ======================================================================= - - Creative Commons is not a party to its public licenses. - Notwithstanding, Creative Commons may elect to apply one of its public - licenses to material it publishes and in those instances will be - considered the "Licensor." Except for the limited purpose of indicating - that material is shared under a Creative Commons public license or as - otherwise permitted by the Creative Commons policies published at - creativecommons.org/policies, Creative Commons does not authorize the - use of the trademark "Creative Commons" or any other trademark or logo - of Creative Commons without its prior written consent including, - without limitation, in connection with any unauthorized modifications - to any of its public licenses or any other arrangements, - understandings, or agreements concerning use of licensed material. For - the avoidance of doubt, this paragraph does not form part of the public - licenses. - - Creative Commons may be contacted at creativecommons.org. diff --git a/docs/README.md b/docs/README.md deleted file mode 100644 index 05980d3818..0000000000 --- a/docs/README.md +++ /dev/null @@ -1,9 +0,0 @@ -# Documentation - -## Building - -You need Jekyll and appledoc. See `build.sh`. - -## License - -See LICENSE.md. diff --git a/docs/_config.yml b/docs/_config.yml deleted file mode 100644 index 0d5f309f67..0000000000 --- a/docs/_config.yml +++ /dev/null @@ -1,13 +0,0 @@ -# Site settings -title: AsyncDisplayKit -description: Smooth asynchronous user interfaces for iOS apps. -baseurl: "" -url: "http://asyncdisplaykit.org" - -# Build settings -highlighter: pygments -markdown: redcarpet - -exclude: -- README.md -- build.sh diff --git a/docs/_includes/footer.html b/docs/_includes/footer.html deleted file mode 100644 index 2714963def..0000000000 --- a/docs/_includes/footer.html +++ /dev/null @@ -1,18 +0,0 @@ -
- -
- - -
- -
diff --git a/docs/_includes/head.html b/docs/_includes/head.html deleted file mode 100644 index a9e7efbdea..0000000000 --- a/docs/_includes/head.html +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - - - - - - - {% if page.title %}{{ page.title }} — {% endif %}AsyncDisplayKit - - - - - - - diff --git a/docs/_includes/header.html b/docs/_includes/header.html deleted file mode 100644 index aebb67cdf1..0000000000 --- a/docs/_includes/header.html +++ /dev/null @@ -1,25 +0,0 @@ - diff --git a/docs/_layouts/default.html b/docs/_layouts/default.html deleted file mode 100644 index bdf5a388da..0000000000 --- a/docs/_layouts/default.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - {% include head.html %} - - - - {% include header.html %} - -
-
- {{ content }} -
-
- - {% include footer.html %} - - - - diff --git a/docs/_layouts/docs.html b/docs/_layouts/docs.html deleted file mode 100644 index 65c07040aa..0000000000 --- a/docs/_layouts/docs.html +++ /dev/null @@ -1,27 +0,0 @@ ---- -layout: default -sectionid: docs ---- -
- -
-

- {{ page.title }} - [edit] -

-
- -
- {{ content }} -
- -
- {% if page.prev %} - ← prev - {% endif %} - {% if page.next %} - next → - {% endif %} -
- -
diff --git a/docs/_layouts/page.html b/docs/_layouts/page.html deleted file mode 100644 index 8e7ccf7a15..0000000000 --- a/docs/_layouts/page.html +++ /dev/null @@ -1,16 +0,0 @@ ---- -layout: default ---- -
- - {% if page.shouldDisplayTitle %} -
-

{{ page.title }}

-
- {% endif %} - -
- {{ content }} -
- -
diff --git a/docs/_layouts/post.html b/docs/_layouts/post.html deleted file mode 100644 index 675596fb1c..0000000000 --- a/docs/_layouts/post.html +++ /dev/null @@ -1,15 +0,0 @@ ---- -layout: default ---- -
- -
-

{{ page.title }}

- -
- -
- {{ content }} -
- -
diff --git a/docs/_sass/_base.scss b/docs/_sass/_base.scss deleted file mode 100644 index 7d353be258..0000000000 --- a/docs/_sass/_base.scss +++ /dev/null @@ -1,205 +0,0 @@ -/** - * Reset some basic elements - */ -body, h1, h2, h3, h4, h5, h6, -p, blockquote, pre, hr, -dl, dd, ol, ul, figure { - margin: 0; - padding: 0; -} - - - -/** - * Basic styling - */ -body { - font-family: $base-font-family; - font-size: $base-font-size; - line-height: $base-line-height; - font-weight: 300; - color: $text-color; - background-color: $background-color; - -webkit-text-size-adjust: 100%; -} - - - -/** - * Set `margin-bottom` to maintain vertical rhythm - */ -h1, h2, h3, h4, h5, h6, -p, blockquote, pre, -ul, ol, dl, figure, -%vertical-rhythm { - margin-bottom: $spacing-unit / 2; -} - - - -/** - * Images - */ -img { - max-width: 100%; - vertical-align: middle; -} - - - -/** - * Figures - */ -figure > img { - display: block; -} - -figcaption { - font-size: $small-font-size; -} - - - -/** - * Lists - */ -ul, ol { - margin-left: $spacing-unit; -} - -li { - > ul, - > ol { - margin-bottom: 0; - } -} - - - -/** - * Headings - */ -h1, h2, h3, h4, h5, h6 { - font-weight: 300; -} - - - -/** - * Links - */ -a { - color: $brand-color; - text-decoration: none; - - &:visited { - color: darken($brand-color, 15%); - } - - &:hover { - color: $text-color; - text-decoration: underline; - } -} - - - -/** - * Blockquotes - */ -blockquote { - color: $grey-color; - border-left: 4px solid $grey-color-light; - padding-left: $spacing-unit / 2; - font-size: 18px; - letter-spacing: -1px; - font-style: italic; - - > :last-child { - margin-bottom: 0; - } -} - - - -/** - * Code formatting - */ -pre, -code { - font-family: Monaco, monospace; - font-size: 14px; - border: 1px solid #afe4ff; - border-radius: 3px; - background-color: #fafdff; -} - -code { - padding: 1px 5px; -} - -pre { - padding: 8px 12px; - overflow-x: scroll; - - > code { - border: 0; - padding-right: 0; - padding-left: 0; - } -} - - - -/** - * Wrapper - */ -.wrapper { - max-width: -webkit-calc(800px - (#{$spacing-unit} * 2)); - max-width: calc(800px - (#{$spacing-unit} * 2)); - margin-right: auto; - margin-left: auto; - padding-right: $spacing-unit; - padding-left: $spacing-unit; - @extend %clearfix; - - @include media-query($on-laptop) { - max-width: -webkit-calc(800px - (#{$spacing-unit})); - max-width: calc(800px - (#{$spacing-unit})); - padding-right: $spacing-unit / 2; - padding-left: $spacing-unit / 2; - } -} - - - -/** - * Clearfix - */ -%clearfix { - - &:after { - content: ""; - display: table; - clear: both; - } -} - - - -/** - * Icons - */ -.icon { - - > svg { - display: inline-block; - width: 16px; - height: 16px; - vertical-align: middle; - - path { - fill: $grey-color; - } - } -} diff --git a/docs/_sass/_layout.scss b/docs/_sass/_layout.scss deleted file mode 100644 index 2eb740fa67..0000000000 --- a/docs/_sass/_layout.scss +++ /dev/null @@ -1,265 +0,0 @@ -/** - * Site header - */ -.site-header { - border-top: 5px solid $grey-color-dark; - border-bottom: 1px solid $grey-color-light; - min-height: 56px; - background-color: #f8f8f8; - - // Positioning context for the mobile navigation icon - position: relative; -} - -.site-title { - font-size: 26px; - line-height: 56px; - letter-spacing: -1px; - margin-bottom: 0; - float: left; - - &, - &:visited { - color: $grey-color-dark; - } - &:hover { - text-decoration: none; - } -} - -.site-nav { - float: right; - line-height: 56px; - - .menu-icon { - display: none; - } - - .page-link { - color: $grey-color; - line-height: $base-line-height; - - // Gaps between nav items, but not on the first one - &:not(:first-child) { - margin-left: 20px; - } - - &:hover { - color: $text-color; - } - } - - .page-link-active { - color: $text-color; - } - - @include media-query($on-palm) { - position: absolute; - top: 9px; - right: 30px; - background-color: $background-color; - border: 1px solid $grey-color-light; - border-radius: 5px; - text-align: right; - - .menu-icon { - display: block; - float: right; - width: 36px; - height: 26px; - line-height: 0; - padding-top: 10px; - text-align: center; - - > svg { - width: 18px; - height: 15px; - - path { - fill: $grey-color-dark; - } - } - } - - .trigger { - clear: both; - display: none; - } - - &:hover .trigger { - display: block; - padding-bottom: 5px; - } - - .page-link { - display: block; - padding: 5px 10px; - } - } -} - - - -/** - * Site footer - */ -.site-footer { - border-top: 1px solid $grey-color-light; - padding: $spacing-unit 0; -} - -.footer-heading { - font-size: 18px; - margin-bottom: $spacing-unit / 2; -} - -.contact-list, -.social-media-list { - list-style: none; - margin-left: 0; -} - -.footer-col-wrapper { - font-size: 11px; - color: $grey-color; - margin-left: -$spacing-unit / 2; - @extend %clearfix; -} - -.footer-col { - float: left; - margin-bottom: $spacing-unit / 2; - padding-left: $spacing-unit / 2; -} - -.footer-col-left { - width: -webkit-calc(50% - (#{$spacing-unit} / 2)); - width: calc(50% - (#{$spacing-unit} / 2)); -} - -.footer-col-right { - text-align: right; - width: -webkit-calc(50% - (#{$spacing-unit} / 2)); - width: calc(50% - (#{$spacing-unit} / 2)); -} - -@include media-query($on-laptop) { - .footer-col-left { - width: -webkit-calc(50% - (#{$spacing-unit} / 2)); - width: calc(50% - (#{$spacing-unit} / 2)); - } - - .footer-col-right { - width: -webkit-calc(100% - (#{$spacing-unit} / 2)); - width: calc(100% - (#{$spacing-unit} / 2)); - } -} - -@include media-query($on-palm) { - .footer-col { - float: none; - width: -webkit-calc(100% - (#{$spacing-unit} / 2)); - width: calc(100% - (#{$spacing-unit} / 2)); - } -} - - - -/** - * Page content - */ -.page-content { - padding: $spacing-unit 0; - background-color: white; -} - -.page-heading { - font-size: 20px; -} - -.post-list { - margin-left: 0; - list-style: none; - - > li { - margin-bottom: $spacing-unit; - } -} - -.post-meta { - font-size: $small-font-size; - color: $grey-color; -} - -.post-link { - display: block; - font-size: 24px; -} - - - -/** - * Posts - */ -.post-header { - margin-bottom: $spacing-unit; -} - -.post-title { - font-size: 42px; - letter-spacing: -1px; - line-height: 1; - - @include media-query($on-laptop) { - font-size: 36px; - } - - .edit-page-link { - font-size: 18px; - } -} - -.post-content { - margin-bottom: $spacing-unit; - - h2 { - font-size: 32px; - - @include media-query($on-laptop) { - font-size: 28px; - } - } - - h3 { - font-size: 26px; - - @include media-query($on-laptop) { - font-size: 22px; - } - } - - h4 { - font-size: 20px; - - @include media-query($on-laptop) { - font-size: 18px; - } - } -} - - - -/** - * Docs - */ -.docs-prevnext { - @extend %clearfix; -} - -.docs-prev { - float: left; -} - -.docs-next { - float: right; -} diff --git a/docs/_sass/_syntax-highlighting.scss b/docs/_sass/_syntax-highlighting.scss deleted file mode 100644 index 3758fdb458..0000000000 --- a/docs/_sass/_syntax-highlighting.scss +++ /dev/null @@ -1,76 +0,0 @@ -/** - * Syntax highlighting styles - */ - -/* not official Xcode colors, but looks better on the web */ -$xc-black: black; -$xc-green: #008d14; -$xc-red: #b72748; -$xc-blue: #103ffb; -$xc-turquoise: #3a95ba; - -.highlight { - background: #fff; - @extend %vertical-rhythm; - - .c { color: $xc-green; font-style: italic } // Comment - .err { color: #a61717; background-color: #e3d2d2 } // Error - .k { color: $xc-blue} // Keyword - .o { } // Operator - .cm { color: $xc-green; font-style: italic } // Comment.Multiline - .cp { color: $xc-red} // Comment.Preproc - .c1 { color: $xc-green; font-style: italic } // Comment.Single - .cs { color: $xc-green; font-weight: bold; font-style: italic } // Comment.Special - .gd { color: #000; background-color: #fdd } // Generic.Deleted - .gd .x { color: #000; background-color: #faa } // Generic.Deleted.Specific - .ge { font-style: italic } // Generic.Emph - .gr { color: #a00 } // Generic.Error - .gh { color: #999 } // Generic.Heading - .gi { color: #000; background-color: #dfd } // Generic.Inserted - .gi .x { color: #000; background-color: #afa } // Generic.Inserted.Specific - .go { color: #888 } // Generic.Output - .gp { color: #555 } // Generic.Prompt - .gs { font-weight: bold } // Generic.Strong - .gu { color: #aaa } // Generic.Subheading - .gt { color: #a00 } // Generic.Traceback - .kc { color: orange} // Keyword.Constant - .kd { color: orange} // Keyword.Declaration - .kp { color: $xc-green} // Keyword.Pseudo - .kr { color: $xc-green} // Keyword.Reserved - .kt { color: $xc-blue} // Keyword.Type - .m { color: orange } // Literal.Number - .s { color: $xc-red } // Literal.String - .na { color: orange } // Name.Attribute - .nb { color: $xc-blue } // Name.Builtin - .nc { color: $xc-turquoise } // Name.Class - .no { color: orange } // Name.Constant - .ni { color: orange } // Name.Entity - .ne { color: orange } // Name.Exception - .nf { } // Name.Function - .nn { color: orange } // Name.Namespace - .nt { color: orange } // Name.Tag - .nv { } // Name.Variable - .ow { } // Operator.Word - .w { color: #bbb } // Text.Whitespace - .mf {} // Literal.Number.Float - .mh { color: $xc-black } // Literal.Number.Hex - .mi { color: $xc-black } // Literal.Number.Integer - .mo { color: $xc-black } // Literal.Number.Oct - .il { color: $xc-black } // Literal.Number.Integer.Long - .sb { color: #d14 } // Literal.String.Backtick - .sc { color: #d14 } // Literal.String.Char - .sd { color: #d14 } // Literal.String.Doc - .s2 { color: #d14 } // Literal.String.Double - .se { color: #d14 } // Literal.String.Escape - .sh { color: #d14 } // Literal.String.Heredoc - .si { color: #d14 } // Literal.String.Interpol - .sx { color: #d14 } // Literal.String.Other - .sr { color: orange } // Literal.String.Regex - .s1 { color: $xc-red } // Literal.String.Single - .ss { color: $xc-red } // Literal.String.Symbol - .bp { color: $xc-turquoise } // Name.Builtin.Pseudo - .vc { color: $xc-turquoise } // Name.Variable.Class - .vg { color: $xc-black } // Name.Variable.Global - .vi { color: orange } // Name.Variable.Instance - .nl { color: $xc-turquoise } -} diff --git a/docs/assets/guide/1-shuffle-crop.png b/docs/assets/guide/1-shuffle-crop.png deleted file mode 100644 index d1e0a83b0c3c23ee7ae938f88dbc1bebd1f27246..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1016 zcmeAS@N?(olHy`uVBq!ia0y~yVB7>`>u|6ENrnvD*+5dT#5JNMI6tkVJh3R1p&&0k zxu~=_!=cpkGXn$jB2O2`kcwMxZ~J!mRm&Xs_};iY&1Un1je<(9C!d&UW^G$>v%+)X zo+C?KIyKyq)KW7hi5zu0>2@efY{{~WBTj)zulO`CP2ug%G@ALSa$d2xeewC3&(F=h zy>n-2{J!~CbFV+Q{5oe@{_{Eiuc&(-O5tjCQr!KE{qwFfRb{JYC+uC9R=Mcq@-utN zcG_)@n}0LTx>xpd@g$X4k4ygp76!avtYg%2`1-qM(aJfN%jVpSo13uH>g1FwI_fiX zJ1OZfs&pZJ}bs zX11v4WL$hKC0e^h&GWAcX&igRove_L54T-D0R z?*7rcvtHiH`thIM-j6RfuH@X7|9uw7*u-Nz72ov^UAo4mA9rAi=7%?uXXbLd_Z=y$ z{&t{OdUAcZGqX-4Q)%gjlFS_KsR;*}W*Ddc**IPA;4qzs&OJFbe=P29D_D5l*(fE*@9$rO;gu28wiO2Vj*D^`)K>ARSQZ?3tte@vxtv$}(fnz@e!1 zavq)oD}y)W%>_B&Qv8OhQlH4r&wAzg;vVkME-0f`@ZX99t7%_)q5S zS)dRoIl>YeG&!QCJx^e&QGp3T(=JTt-{Lyf_xt`VW4m~78z@J6y85}Sb4q9e0NQ!% A6951J diff --git a/docs/assets/guide/1-shuffle.png b/docs/assets/guide/1-shuffle.png deleted file mode 100644 index 9188eebf8ae9edd78fadd80b1a8f994e116c88e4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 19288 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 diff --git a/docs/assets/logo-square.png b/docs/assets/logo-square.png deleted file mode 100755 index 82ad66c69ecdd8626cdd380e5c536dbcaeb0a0fc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 66422 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

Axt>VUn+{%`lVxh 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 diff --git a/docs/assets/logo.png b/docs/assets/logo.png deleted file mode 100755 index dce1ebc95066e56bf72c591027b7776b767a5786..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 105684 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

AgH(i{EZ2lp^1>P->`lX~`! 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 diff --git a/docs/build.sh b/docs/build.sh deleted file mode 100755 index c532bb0d6b..0000000000 --- a/docs/build.sh +++ /dev/null @@ -1,33 +0,0 @@ -#!/bin/sh -set -e - -HEADERS=`ls ../AsyncDisplayKit/*.h ../AsyncDisplayKit/Details/ASRangeController.h ../AsyncDisplayKit/Layout/*.h` - -rm -rf htdocs appledoc - -jekyll build --destination htdocs - -appledoc \ - --no-create-docset \ - --create-html \ - --exit-threshold 2 \ - --no-repeat-first-par \ - --no-merge-categories \ - --explicit-crossref \ - --warn-missing-output-path \ - --warn-missing-company-id \ - --warn-undocumented-object \ - --warn-undocumented-member \ - --warn-empty-description \ - --warn-unknown-directive \ - --warn-invalid-crossref \ - --warn-missing-arg \ - --project-name AsyncDisplayKit \ - --project-company Facebook \ - --company-id "com.facebook" \ - --output appledoc \ - $HEADERS - -mv appledoc/html htdocs/appledoc - -rmdir appledoc diff --git a/docs/css/main.scss b/docs/css/main.scss deleted file mode 100755 index 4417ff0713..0000000000 --- a/docs/css/main.scss +++ /dev/null @@ -1,49 +0,0 @@ ---- -# Only the main Sass file needs front matter (the dashes are enough) ---- -@charset "utf-8"; - - - -// Our variables -$base-font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; -$base-font-size: 16px; -$small-font-size: $base-font-size * 0.875; -$base-line-height: 1.5; - -$spacing-unit: 30px; - -$text-color: #111; -$background-color: #f8f8f8; -$brand-color: #21b6ff; - -$grey-color: #828282; -$grey-color-light: lighten($grey-color, 40%); -$grey-color-dark: darken($grey-color, 25%); - -$on-palm: 600px; -$on-laptop: 800px; - - - -// Using media queries with like this: -// @include media-query($palm) { -// .wrapper { -// padding-right: $spacing-unit / 2; -// padding-left: $spacing-unit / 2; -// } -// } -@mixin media-query($device) { - @media screen and (max-width: $device) { - @content; - } -} - - - -// Import partials from `sass_dir` (defaults to `_sass`) -@import - "base", - "layout", - "syntax-highlighting" -; diff --git a/docs/guide/1-introduction.md b/docs/guide/1-introduction.md deleted file mode 100644 index d923c0a215..0000000000 --- a/docs/guide/1-introduction.md +++ /dev/null @@ -1,150 +0,0 @@ ---- -layout: docs -title: Getting started -permalink: /guide/ -next: guide/2/ ---- - -## Concepts - -AsyncDisplayKit's basic unit is the *node*. ASDisplayNode is an abstraction -over UIView, which in turn is an abstraction over CALayer. Unlike views, which -can only be used on the main thread, nodes are thread-safe: you can -instantiate and configure entire hierarchies of them in parallel on background -threads. - -To keep its user interface smooth and responsive, your app should render at 60 -frames per second — the gold standard on iOS. This means the main thread -has one-sixtieth of a second to push each frame. That's 16 milliseconds to -execute all layout and drawing code! And because of system overhead, your code -usually has less than ten milliseconds to run before it causes a frame drop. - -AsyncDisplayKit lets you move image decoding, text sizing and rendering, and -other expensive UI operations off the main thread. It has other tricks up its -sleeve too... but we'll get to that later. :] - -## Nodes as drop-in view replacements - -If you're used to working with views, you already know how to use nodes. The -node API is similar to UIView's, with some additional conveniences — for -example, you can access common CALayer properties directly. To add a node to -an existing view or layer hierarchy, use its `node.view` or `node.layer`. - -AsyncDisplayKit's core components include: - -* *ASDisplayNode*. Counterpart to UIView — subclass to make custom nodes. -* *ASControlNode*. Analogous to UIControl — subclass to make buttons. -* *ASImageNode*. Like UIImageView — decodes images asynchronously. -* *ASTextNode*. Like UITextView — built on TextKit with full-featured - rich text support. -* *ASTableView* and *ASCollectionView*. UITableView and UICollectionView - subclasses that support nodes. - -You can use these as drop-in replacements for their UIKit counterparts. While -ASDK works most effectively with fully node-based hierarchies, even replacing -individual views with nodes can improve performance. - -Let's look at an example. - -We'll start out by using nodes synchronously on the main thread — the -same way you already use views. This code is a familiar sight in custom view -controller `-loadView` implementations: - -```objective-c -_imageView = [[UIImageView alloc] init]; -_imageView.image = [UIImage imageNamed:@"hello"]; -_imageView.frame = CGRectMake(10.0f, 10.0f, 40.0f, 40.0f); -[self.view addSubview:_imageView]; -``` - -We can replace it with the following node-based code: - -```objective-c -_imageNode = [[ASImageNode alloc] init]; -_imageNode.backgroundColor = [UIColor lightGrayColor]; -_imageNode.image = [UIImage imageNamed:@"hello"]; -_imageNode.frame = CGRectMake(10.0f, 10.0f, 40.0f, 40.0f); -[self.view addSubview:_imageNode.view]; -``` - -This doesn't take advantage of ASDK's asynchronous sizing and layout -functionality, but it's already an improvement. The first block of code -synchronously decodes `hello.png` on the main thread; the second starts -decoding the image on a background thread, possibly on a different CPU core. - -(Note that we're setting a placeholder background colour on the node, "holding -its place" onscreen until the real content appears. This works well with -images but less so with text — people expect text to appear instantly, -with images loading in after a slight delay. We'll discuss techniques to -improve this later on.) - -## Button nodes - -ASImageNode and ASTextNode both inherit from ASControlNode, so you can use them -as buttons. Let's say we're making a music player and we want to add a -(non-skeuomorphic, iOS 7-style) shuffle button: - -[![shuffle]({{ site.baseurl }}/assets/guide/1-shuffle-crop.png)]({{ site.baseurl }}/assets/guide/1-shuffle.png) - -Our view controller will look something like this: - -```objective-c -- (void)viewDidLoad -{ - [super viewDidLoad]; - - // attribute a string - NSDictionary *attrs = @{ - NSFontAttributeName: [UIFont systemFontOfSize:12.0f], - NSForegroundColorAttributeName: [UIColor redColor], - }; - NSAttributedString *string = [[NSAttributedString alloc] initWithString:@"shuffle" - attributes:attrs]; - - // create the node - _shuffleNode = [[ASTextNode alloc] init]; - _shuffleNode.attributedString = string; - - // configure the button - _shuffleNode.userInteractionEnabled = YES; // opt into touch handling - [_shuffleNode addTarget:self - action:@selector(buttonTapped:) - forControlEvents:ASControlNodeEventTouchUpInside]; - - // size all the things - CGRect b = self.view.bounds; // convenience - CGSize size = [_shuffleNode measure:CGSizeMake(b.size.width, FLT_MAX)]; - CGPoint origin = CGPointMake(roundf( (b.size.width - size.width) / 2.0f ), - roundf( (b.size.height - size.height) / 2.0f )); - _shuffleNode.frame = (CGRect){ origin, size }; - - // add to our view - [self.view addSubview:_shuffleNode.view]; -} - -- (void)buttonTapped:(id)sender -{ - NSLog(@"tapped!"); -} -``` - -This works as you would expect. Unfortunately, this button is only 14½ -points tall — nowhere near the standard 44×44 minimum tap target -size — and it's very difficult to tap. We could solve this by -subclassing the text node and overriding `-hitTest:withEvent:`. We could even -force the text view to have a minimum height during layout. But wouldn't it be -nice if there were a more elegant way? - -```objective-c - // size all the things - /* ... */ - - // make the tap target taller - CGFloat extendY = roundf( (44.0f - size.height) / 2.0f ); - _shuffleNode.hitTestSlop = UIEdgeInsetsMake(-extendY, 0.0f, -extendY, 0.0f); -``` - -Et voilà! *Hit-test slops* work on all nodes, and are a nice example of what -this new abstraction enables. - -Next up, making your own nodes! diff --git a/docs/guide/2-custom-nodes.md b/docs/guide/2-custom-nodes.md deleted file mode 100644 index 6d67ed3a05..0000000000 --- a/docs/guide/2-custom-nodes.md +++ /dev/null @@ -1,211 +0,0 @@ ---- -layout: docs -title: Custom nodes -permalink: /guide/2/ -prev: guide/ -next: guide/3/ ---- - -## View hierarchies - -Sizing and layout of custom view hierarchies are typically done all at once on -the main thread. For example, a custom UIView that minimally encloses a text -view and an image view might look like this: - -```objective-c -- (CGSize)sizeThatFits:(CGSize)size -{ - // size the image - CGSize imageSize = [_imageView sizeThatFits:size]; - - // size the text view - CGSize maxTextSize = CGSizeMake(size.width - imageSize.width, size.height); - CGSize textSize = [_textView sizeThatFits:maxTextSize]; - - // make sure everything fits - CGFloat minHeight = MAX(imageSize.height, textSize.height); - return CGSizeMake(size.width, minHeight); -} - -- (void)layoutSubviews -{ - CGSize size = self.bounds.size; // convenience - - // size and layout the image - CGSize imageSize = [_imageView sizeThatFits:size]; - _imageView.frame = CGRectMake(size.width - imageSize.width, 0.0f, - imageSize.width, imageSize.height); - - // size and layout the text view - CGSize maxTextSize = CGSizeMake(size.width - imageSize.width, size.height); - CGSize textSize = [_textView sizeThatFits:maxTextSize]; - _textView.frame = (CGRect){ CGPointZero, textSize }; -} -``` - -This isn't ideal. We're sizing our subviews twice — once to figure out -how big our view needs to be and once when laying it out — and while our -layout arithmetic is cheap and quick, we're also blocking the main thread on -expensive text sizing. - -We could improve the situation by manually cacheing our subviews' sizes, but -that solution comes with its own set of problems. Just adding `_imageSize` and -`_textSize` ivars wouldn't be enough: for example, if the text were to change, -we'd need to recompute its size. The boilerplate would quickly become -untenable. - -Further, even with a cache, we'll still be blocking the main thread on sizing -*sometimes*. We could try to shift sizing to a background thread with -`dispatch_async()`, but even if our own code is thread-safe, UIView methods are -documented to [only work on the main -thread](https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIView_Class/index.html): - -> Manipulations to your application’s user interface must occur on the main -> thread. Thus, you should always call the methods of the UIView class from -> code running in the main thread of your application. The only time this may -> not be strictly necessary is when creating the view object itself but all -> other manipulations should occur on the main thread. - -This is a pretty deep rabbit hole. We could attempt to work around the fact -that UILabels and UITextViews cannot safely be sized on background threads by -manually creating a TextKit stack and sizing the text ourselves... but that's a -laborious duplication of work. Further, if UITextView's layout behaviour -changes in an iOS update, our sizing code will break. (And did we mention that -TextKit isn't thread-safe either?) - -## Node hierarchies - -Enter AsyncDisplayKit. Our custom node looks like this: - -```objective-c -#import - -... - -// perform expensive sizing operations on a background thread -- (CGSize)calculateSizeThatFits:(CGSize)constrainedSize -{ - // size the image - CGSize imageSize = [_imageNode measure:constrainedSize]; - - // size the text node - CGSize maxTextSize = CGSizeMake(constrainedSize.width - imageSize.width, - constrainedSize.height); - CGSize textSize = [_textNode measure:maxTextSize]; - - // make sure everything fits - CGFloat minHeight = MAX(imageSize.height, textSize.height); - return CGSizeMake(constrainedSize.width, minHeight); -} - -// do as little work as possible in main-thread layout -- (void)layout -{ - // layout the image using its cached size - CGSize imageSize = _imageNode.calculatedSize; - _imageNode.frame = CGRectMake(self.bounds.size.width - imageSize.width, 0.0f, - imageSize.width, imageSize.height); - - // layout the text view using its cached size - CGSize textSize = _textNode.calculatedSize; - _textNode.frame = (CGRect){ CGPointZero, textSize }; -} -``` - -ASImageNode and ASTextNode, like the rest of AsyncDisplayKit, are thread-safe, -so we can size them on background threads. The `-measure:` method is like -`-sizeThatFits:`, but with side effects: it caches both the argument -(`constrainedSizeForCalculatedSize`) and the result (`calculatedSize`) for -quick access later on — like in our now-snappy `-layout` implementation. - -As you can see, node hierarchies are sized and laid out in much the same way as -their view counterparts. Custom nodes do need to be written with a few things -in mind: - -* Nodes must recursively measure all of their subnodes in their - `-calculateSizeThatFits:` implementations. Note that the `-measure:` - machinery will only call `-calculateSizeThatFits:` if a new measurement pass - is needed (e.g., if the constrained size has changed). - -* Nodes should perform any other expensive pre-layout calculations in - `-calculateSizeThatFits:`, cacheing useful intermediate results in ivars as - appropriate. - -* Nodes should call `[self invalidateCalculatedSize]` when necessary. For - example, ASTextNode invalidates its calculated size when its - `attributedString` property is changed. - -For more examples of custom sizing and layout, along with a demo of -ASTextNode's features, check out `BlurbNode` and `KittenNode` in the -[Kittens](https://github.com/facebook/AsyncDisplayKit/tree/master/examples/Kittens) -sample project. - -## Custom drawing - -To guarantee thread safety in its highly-concurrent drawing system, the node -drawing API diverges substantially from UIView's. Instead of implementing -`-drawRect:`, you must: - -1. Define an internal "draw parameters" class for your custom node. This - class should be able to store any state your node needs to draw itself - — it can be a plain old NSObject or even a dictionary. - -2. Return a configured instance of your draw parameters class in - `-drawParametersForAsyncLayer:`. This method will always be called on the - main thread. - -3. Implement either `+drawRect:withParameters:isCancelled:isRasterizing:` or - `+displayWithParameters:isCancelled:`. Note that these are *class* methods - that will not have access to your node's state — only the draw - parameters object. They can be called on any thread and must be - thread-safe. - -For example, this node will draw a rainbow: - -```objective-c -@interface RainbowNode : ASDisplayNode -@end - -@implementation RainbowNode - -+ (void)drawRect:(CGRect)bounds - withParameters:(id)parameters - isCancelled:(asdisplaynode_iscancelled_block_t)isCancelledBlock - isRasterizing:(BOOL)isRasterizing -{ - // clear the backing store, but only if we're not rasterising into another layer - if (!isRasterizing) { - [[UIColor whiteColor] set]; - UIRectFill(bounds); - } - - // UIColor sadly lacks +indigoColor and +violetColor methods - NSArray *colors = @[ [UIColor redColor], - [UIColor orangeColor], - [UIColor yellowColor], - [UIColor greenColor], - [UIColor blueColor], - [UIColor purpleColor] ]; - CGFloat stripeHeight = roundf(bounds.size.height / (float)colors.count); - - // draw the stripes - for (UIColor *color in colors) { - CGRect stripe = CGRectZero; - CGRectDivide(bounds, &stripe, &bounds, stripeHeight, CGRectMinYEdge); - [color set]; - UIRectFill(stripe); - } -} - -@end -``` - -This could easily be extended to support vertical rainbows too, by adding a -`vertical` property to the node, exporting it in -`-drawParametersForAsyncLayer:`, and referencing it in -`+drawRect:withParameters:isCancelled:isRasterizing:`. More-complex nodes can -be supported in much the same way. - -For more on custom nodes, check out the [subclassing -header](https://github.com/facebook/AsyncDisplayKit/blob/master/AsyncDisplayKit/ASDisplayNode%2BSubclasses.h) -or read on! diff --git a/docs/guide/3-asynchronous-display.md b/docs/guide/3-asynchronous-display.md deleted file mode 100644 index acc9f37911..0000000000 --- a/docs/guide/3-asynchronous-display.md +++ /dev/null @@ -1,102 +0,0 @@ ---- -layout: docs -title: Asynchronous display -permalink: /guide/3/ -prev: guide/2/ -next: guide/4/ ---- - -## Realistic placeholders - -Nodes need to complete both a *measurement pass* and a *display pass* before -they're fully rendered. It's possible to force either step to happen -synchronously: call `-measure:` in `-layoutSubviews` to perform sizing on the -main thread, or set a node's `displaysAsynchronously` flag to NO to disable -ASDK's async display machinery. (AsyncDisplayKit can still improve your app's -performance even when rendering fully synchronously — more on that -later!) - -The recommended way to use ASDK is to only add nodes to your view hierarchy -once they've been sized. This avoids unsightly layout changes as the -measurement pass completes, but if you enable asynchronous display, it will -always be possible for a node to appear onscreen before its content has fully -rendered. We'll discuss techniques to minimise this shortly, but you should -take it into account and include *realistic placeholders* in your app designs. - -Once its measurement pass has completed, a node can accurately place all of its -subnodes onscreen — they'll just be blank. The easiest way to make a -realistic placeholder is to set static background colours on your subnodes. -This effect looks better than generic placeholder images because it varies -based on the content being loaded, and it works particularly well for opaque -images. You can also create visually-appealing placeholder nodes, like the -shimmery lines representing text in Paper as its stories are loaded, and swap -them out with your content nodes once they've finished displaying. - -## Working range - -So far, we've only discussed asynchronous sizing: toss a "create a node -hierarchy and measure it" block onto a background thread, then trampoline to -the main thread to add it to the view hierarchy when that's done. Ideally, as -much content as possible should be fully-rendered and ready to go as soon as -the user scrolls to it. This requires triggering display passes in advance. - -If your app's content is in a scroll view or can be paged through, like -Instagram's main feed or Paper's story strip, the solution is a *working -range*. A working range controller tracks the *visible range*, the subset of -content that's currently visible onscreen, and enqueues asynchronous rendering -for the next few screenfuls of content. As the user scrolls, a screenful or -two of previous content is preserved; the rest is cleared to conserve memory. -If she starts scrolling in the other direction, the working range trashes its -render queue and starts pre-rendering in the new direction of scroll — -and because of the buffer of previous content, this entire process will -typically be invisible. - -AsyncDisplayKit includes a generic working range controller, -`ASRangeController`. Its working range size can be tuned depending on your -app: if your nodes are simple, even an iPhone 4 can maintain a substantial -working range, but heavyweight nodes like Facebook stories are expensive and -need to be pruned quickly. - -```objective-c -ASRangeController *rangeController = [[ASRangeController alloc] init]; -rangeController.tuningParameters = (ASRangeTuningParameters){ - .leadingBufferScreenfuls = 2.0f; // two screenfuls in the direction of scroll - .trailingBufferScreenfuls = 0.5f; // one-half screenful in the other direction -}; -``` - -If you use a working range, you should profile your app and consider tuning it -differently on a per-device basis. iPhone 4 has 512MB of RAM and a single-core -A4 chipset, while iPhone 6 has 1GB of RAM and the orders-of-magnitude-faster -multicore A8 — and if your app supports iOS 7, it will be used on both. - -## ASTableView - -ASRangeController manages working ranges, but doesn't actually display content. -If your content is currently rendered in a UITableView, you can convert it to -use `ASTableView` and custom nodes — just subclass `ASCellNode` instead -of ASDisplayNode. ASTableView is a UITableView subclass that integrates -node-based cells and a working range. - -ASTableView doesn't let cells onscreen until their underlying nodes have been -sized, and as such can fully benefit from realistic placeholders. Its API is -very similar to UITableView (see the -[Kittens](https://github.com/facebook/AsyncDisplayKit/tree/master/examples/Kittens) -sample project for an example), with some key changes: - -* Rather than setting the table view's `.delegate` and `.dataSource`, you set - its `.asyncDelegate` and `.asyncDataSource`. See - [ASTableView.h](https://github.com/facebook/AsyncDisplayKit/blob/master/AsyncDisplayKit/ASTableView.h) - for how its delegate and data source protocols differ from UITableView's. - -* Instead of implementing `-tableView:cellForRowAtIndexPath:`, your data - source must implement `-tableView:nodeForRowAtIndexPath:`. This method must - be thread-safe and should not implement reuse. Unlike the UITableView - version, it won't be called when the row is about to display. - -* `-tableView:heightForRowAtIndexPath:` has been removed — ASTableView - lets your cell nodes size themselves. This means you no longer have to - manually duplicate or factor out layout and sizing logic for - dynamically-sized UITableViewCells! - -Next up, how to get the most out of ASDK in your app. diff --git a/docs/guide/4-making-the-most-of-asdk.md b/docs/guide/4-making-the-most-of-asdk.md deleted file mode 100644 index f35ad900b4..0000000000 --- a/docs/guide/4-making-the-most-of-asdk.md +++ /dev/null @@ -1,139 +0,0 @@ ---- -layout: docs -title: Making the most of AsyncDisplayKit -permalink: /guide/4/ -prev: guide/3/ -next: guide/5/ ---- - -## A note on optimisation - -AsyncDisplayKit is powerful and flexible, but it is not a panacea. If your app -has a complex image- or text-heavy user interface, ASDK can definitely help -improve its performance — but if you're blocking the main thread on -network requests, you should consider rearchitecting a few things first. :] - -So why is it worthwhile to change the way we do view layout and rendering, -given that UIKit has always been locked to the main thread and performant iOS -apps have been shipping since iPhone's launch? - -### Modern animations - -Until iOS 7, static animations (à la `+[UIView -animateWithDuration:animations:]`) were the standard. The post-skeuomorphism -redesign brought with it highly-interactive, physics-based animations, with -springs joining the ranks of constant animation functions like -`UIViewAnimationOptionCurveEaseInOut`. - -Classic animations aren't actually executed in your app. They're executed -out-of-process, in the high-priority Core Animation render server. Thanks to -pre-emptive multitasking, an app can block its main thread continuously without -causing the animation to drop a single frame. - -Critically, dynamic animations can't be offloaded the same way, and both -[pop](https://github.com/facebook/pop) and UIKit Dynamics execute physics -simulations on your app's main thread. This is because executing arbitrary -code in the render server would introduce unacceptable latency, even if it -could be done securely. - -Physics-based animations are often interactive, letting you start an animation -and interrupt it before it completes. Paper lets you fling objects across the -screen and catch them before they land, or grab a view that's being pulled by a -spring and tear it off. This requires processing touch events and updating -animation targets in realtime — even short delays for inter-process -communication would shatter the illusion. - -(Fun fact: Inertial scrolling is also a physics animation! UIScrollView has -always implemented its animations on the main thread, which is why stuttery -scrolling is the hallmark of a slow app.) - -### The main-thread bottleneck - -Physics animations aren't the only thing that need to happen on the main -thread. The main thread's [run -loop](https://developer.apple.com/library/ios/documentation/cocoa/conceptual/multithreading/runloopmanagement/runloopmanagement.html) -is responsible for handling touch events and initiating drawing operations -— and with UIKit in the mix, it also has to render text, decode images, -and do any other custom drawing (e.g., using Core Graphics). - -If an iteration of the main thread's run loop takes too long, it will drop an -animation frame and may fail to handle touch events in time. Each iteration of -the run loop must complete within 16ms in order to drive 60fps animations, and -your own code typically has less than 10ms to execute. This means that the -best way to keep your app smooth and responsive is to do as little work on the -main thread as possible. - -What's more, the main thread only executes on one core! Single-threaded view -hierarchies can't take advantage of the multicore CPUs in all modern iOS -devices. This is important for more than just performance reasons — it's -also critical for battery life. Running the CPU on all cores for a short time -is preferable to running one core for an extended amount of time: if the -processor can *race to sleep* by finishing its work and idling faster, it can -spend more time in a low-power mode, improving battery life. - -## When to go asynchronous - -AsyncDisplayKit really shines when used fully asynchronously, shifting both -measurement and rendering passes off the main thread and onto multiple cores. -This requires a completely node-based hierarchy. Just as degrading from -UIViews to CALayers disables view-specific functionality like touch handling -from that point on, degrading from nodes to views disables async behaviour. - -You don't, however, need to convert your app's entire view hierarchy to nodes. -In fact, you shouldn't! Asynchronously bringing up your app's core UI, like -navigation elements or tab bars, would be a very confusing experience. Those -elements of your apps can still be nodes, but should be fully synchronous to -guarantee a fully-usable interface as quickly as possible. (This is why -UIWindow has no node equivalent.) - -There are two key situations where asynchronous hierarchies excel: - -1. *Parallelisation*. Measuring and rendering UITableViewCells (or your app's - equivalent, e.g., story cards in Paper) are embarrassingly parallel - problems. Table cells typically have a fixed width and variable height - determined by their contents — the argument to `-measure:` for one - cell doesn't depend on any other cells' calculations, so we can enqueue an - arbitrary number of cell measurement passes at once. - -2. *Preloading*. An app with five tabs should synchronously load the first - one so content is ready to go as quickly as possible. Once this is - complete and the CPU is idle, why not asynchronously prepare the other tabs - so the user doesn't have to wait? This is inconvenient with views, but - very easy with nodes. - -Paper's asynchronous rendering starts at the story strip. You should profile -your app and watch how people use it in the wild to decide what combination of -synchrony and asynchrony yields the best user experience. - -## Additional optimisations - -Complex hierarchies — even when rendered asynchronously — can -impose a cost because of the sheer number of views involved. Working around -this can be painful, but AsyncDisplayKit makes it easy! - -* *Layer-backing*. In some cases, you can substantially improve your app's - performance by using layers instead of views. Manually converting - view-based code to layers is laborious due to the difference in APIs. - Worse, if at some point you need to enable touch handling or other - view-specific functionality, you have to manually convert everything back - (and risk regressions!). - - With nodes, converting an entire subtree from views to layers is as simple - as... - - rootNode.layerBacked = YES; - - ...and if you need to go back, it's as simple as deleting one line. We - recommend enabling layer-backing as a matter of course in any custom node - that doesn't need touch handling. - -* *Precompositing*. Flattening an entire view hierarchy into a single layer - also improves performance, but comes with a hit to maintainability and - hierarchy-based reasoning. Nodes can do this for you too! - - rootNode.shouldRasterizeDescendants = YES; - - ...will cause the entire node hierarchy from that point on to be rendered - into one layer. - -Next up: AsyncDisplayKit, under the hood. diff --git a/docs/guide/5-under-the-hood.md b/docs/guide/5-under-the-hood.md deleted file mode 100644 index 01229ec3ff..0000000000 --- a/docs/guide/5-under-the-hood.md +++ /dev/null @@ -1,89 +0,0 @@ ---- -layout: docs -title: Under the hood -permalink: /guide/5/ -prev: guide/4/ ---- - -## Node architecture - -*(Skip to the next section if you're not interested in AsyncDisplayKit implementation details.)* - -We've described nodes as an abstraction over views and layers, and shown how to -interact with the underlying UIViews and CALayers when necessary. Nodes don't -wrap or vend their UIKit counterparts, though — an ASImageNode's `.view` -is not a UIImageView! So how do nodes work? - -**NOTE:** Classes whose names begin with `_` are private. Don't use them -directly! - -Creating a node doesn't create its underlying view-layer pair. This is why you -can create nodes cheaply and on background threads. When you use a UIView or -CALayer property on a node, you're actually interacting with a proxy object, -[`_ASPendingState`](https://github.com/facebook/AsyncDisplayKit/blob/master/AsyncDisplayKit/Private/_ASPendingState.h), -that's preconfigured to match UIView and CALayer defaults. - -The first access to a node's `.view` or `.layer` property causes both to be -initialised and configured with the node's current state. If it has subnodes, -they are recursively loaded as well. Once a node has been loaded, the proxy -object is destroyed and the node becomes main-thread-affined — its -properties will update the underlying view directly. (Layer-backed nodes do -the same, not loading views.) - -Nodes are powered by -[`_ASDisplayLayer`](https://github.com/facebook/AsyncDisplayKit/blob/master/AsyncDisplayKit/Details/_ASDisplayLayer.h) -and -[`_ASDisplayView`](https://github.com/facebook/AsyncDisplayKit/blob/master/AsyncDisplayKit/Details/_ASDisplayView.h). -These are lightweight to create and add to their respective hierarchies, and -provide integration points that allow nodes to act as full-fledged views or -layers. It's possible to create nodes that are backed by custom view or layer -classes, but doing so is strongly discouraged as it disables the majority of -ASDK's functionality. - -When Core Animation asks an `_ASDisplayLayer` to draw itself, the request is -forwarded to its node. Unless asynchronous display has been disabled, the -actual draw call won't happen immediately or on the main thread. Instead, a -display block will be added to a background queue. These blocks are executed -in parallel, but you can enable `ASDISPLAYNODE_DELAY_DISPLAY` in -[`ASDisplayNode(AsyncDisplay)`](https://github.com/facebook/AsyncDisplayKit/blob/master/AsyncDisplayKit/Private/ASDisplayNode%2BAsyncDisplay.mm) -to serialise the render system for debugging. - -Common UIView subclass hooks are forwarded from `_ASDisplayView` to its -underlying node, including touch handling, hit-testing, and gesture recogniser -delegate calls. Because an `_ASDisplayView`'s layer is an `_ASDisplayLayer`, -view-backed nodes also participate in asynchronous display. - -## In practice - -What does this mean for your custom nodes? - -You can implement methods like `-touchesBegan:withEvent:` / -`touchesMoved:withEvent:` / `touchesEnded:withEvent:` / -`touchesCancelled:withEvent:` in your nodes exactly as you would in a UIView -subclass. If you find you need a subclass hook that hasn't already been -provided, please file an issue on GitHub — or add it yourself and submit a -pull request! - -If you need to interact or configure your node's underlying view or layer, -don't do so in `-init`. Instead, override `-didLoad` and check if you're -layer-backed: - -```objective-c -- (void)didLoad -{ - [super didLoad]; - - // add a gesture recogniser, if we have a view to add it to - if (!self.layerBacked) { - _gestureRecogniser = [[UITapGestureRecognizer alloc] initWithTarget:self - action:@selector(_tap:)]; - [self.view addGestureRecognizer:_gestureRecogniser]; - } -} -``` - -## *fin.* - -Thanks for reading! If you have any questions, please file a GitHub issue or -post in the [Facebook group](https://www.facebook.com/groups/551597518288687). -We'd love to hear from you. diff --git a/docs/index.md b/docs/index.md deleted file mode 100644 index ff8065921a..0000000000 --- a/docs/index.md +++ /dev/null @@ -1,86 +0,0 @@ ---- -layout: page -title: Smooth asynchronous user interfaces for iOS apps ---- - -![logo]({{ site.baseurl }}/assets/logo.png) - -AsyncDisplayKit is an iOS framework that keeps even the most complex user -interfaces smooth and responsive. It was originally built to make Facebook's -[Paper](https://facebook.com/paper) possible, and goes hand-in-hand with -[pop](https://github.com/facebook/pop)'s physics-based animations — but -it's just as powerful with UIKit Dynamics and conventional app designs. - - -
-### Quick start - -ASDK is available on [CocoaPods](http://cocoapods.org). Add the following to your Podfile: - -```ruby -pod 'AsyncDisplayKit' -``` - -(ASDK can also be used as a regular static library: Copy the project to your -codebase manually, adding `AsyncDisplayKit.xcodeproj` to your workspace. Add -`libAsyncDisplayKit.a`, AssetsLibrary, and Photos to the "Link Binary With -Libraries" build phase. Include `-lc++ -ObjC` in your project linker flags.) - -Import the framework header, or create an [Objective-C bridging -header](https://developer.apple.com/library/ios/documentation/swift/conceptual/buildingcocoaapps/MixandMatch.html) -if you're using Swift: - -```objective-c -#import -``` - -AsyncDisplayKit Nodes are a thread-safe abstraction layer over UIViews and -CALayers: - -![logo]({{ site.baseurl }}/assets/node-view-layer.png) - -You can construct entire node hierarchies in parallel, or instantiate and size -a single node on a background thread — for example, you could do -something like this in a UIViewController: - -```objective-c -dispatch_async(_backgroundQueue, ^{ - ASTextNode *node = [[ASTextNode alloc] init]; - node.attributedString = [[NSAttributedString alloc] initWithString:@"hello!" - attributes:nil]; - [node measure:CGSizeMake(screenWidth, FLT_MAX)]; - node.frame = (CGRect){ CGPointZero, node.calculatedSize }; - - // self.view isn't a node, so we can only use it on the main thread - dispatch_async(dispatch_get_main_queue(), ^{ - [self.view addSubview:node.view]; - }); -}); -``` - -AsyncDisplayKit at a glance: - -* `ASImageNode` and `ASTextNode` are drop-in replacements for UIImageView and - UITextView. -* `ASMultiplexImageNode` can load and display progressively higher-quality - variants of an image over a slow cell network, letting you quickly show a - low-resolution photo while the full size downloads. -* `ASNetworkImageNode` is a simpler, single-image counterpart to the Multiplex - node. -* `ASTableView` and `ASCollectionView` are a node-aware UITableView and - UICollectionView, respectively, that can asynchronously preload cell nodes - — from loading network data to rendering — all without blocking - the main thread. - -You can also easily [create your own -nodes](https://github.com/facebook/AsyncDisplayKit/blob/master/AsyncDisplayKit/ASDisplayNode%2BSubclasses.h) -to implement node hierarchies or custom drawing. - - -
-### Learn more - -* Read the [Getting Started guide]({{ site.baseurl }}/guide) -* Get the [sample projects](https://github.com/facebook/AsyncDisplayKit/tree/master/examples) -* Browse the [API reference]({{ site.baseurl }}/appledoc) -* Watch the [NSLondon talk](http://vimeo.com/103589245) or the [NSSpain talk](https://www.youtube.com/watch?v=RY_X7l1g79Q) From ae87717263c33b0e3e8c09a9f7f3693f1b6f31fe Mon Sep 17 00:00:00 2001 From: appleguy Date: Sun, 26 Jun 2016 17:12:59 -0700 Subject: [PATCH 15/43] Revert "Remove old website folder from master branch" (#1818) --- docs/CNAME | 2 + docs/LICENSE.md | 420 ++++++++++++++++++++++++ docs/README.md | 9 + docs/_config.yml | 13 + docs/_includes/footer.html | 18 + docs/_includes/head.html | 24 ++ docs/_includes/header.html | 25 ++ docs/_layouts/default.html | 20 ++ docs/_layouts/docs.html | 27 ++ docs/_layouts/page.html | 16 + docs/_layouts/post.html | 15 + docs/_sass/_base.scss | 205 ++++++++++++ docs/_sass/_layout.scss | 265 +++++++++++++++ docs/_sass/_syntax-highlighting.scss | 76 +++++ docs/assets/guide/1-shuffle-crop.png | Bin 0 -> 1016 bytes docs/assets/guide/1-shuffle.png | Bin 0 -> 19288 bytes docs/assets/logo-square.png | Bin 0 -> 66422 bytes docs/assets/logo.png | Bin 0 -> 105684 bytes docs/assets/node-view-layer.png | Bin 0 -> 12961 bytes docs/build.sh | 33 ++ docs/css/main.scss | 49 +++ docs/guide/1-introduction.md | 150 +++++++++ docs/guide/2-custom-nodes.md | 211 ++++++++++++ docs/guide/3-asynchronous-display.md | 102 ++++++ docs/guide/4-making-the-most-of-asdk.md | 139 ++++++++ docs/guide/5-under-the-hood.md | 89 +++++ docs/index.md | 86 +++++ 27 files changed, 1994 insertions(+) create mode 100644 docs/CNAME create mode 100644 docs/LICENSE.md create mode 100644 docs/README.md create mode 100644 docs/_config.yml create mode 100644 docs/_includes/footer.html create mode 100644 docs/_includes/head.html create mode 100644 docs/_includes/header.html create mode 100644 docs/_layouts/default.html create mode 100644 docs/_layouts/docs.html create mode 100644 docs/_layouts/page.html create mode 100644 docs/_layouts/post.html create mode 100644 docs/_sass/_base.scss create mode 100644 docs/_sass/_layout.scss create mode 100644 docs/_sass/_syntax-highlighting.scss create mode 100644 docs/assets/guide/1-shuffle-crop.png create mode 100644 docs/assets/guide/1-shuffle.png create mode 100755 docs/assets/logo-square.png create mode 100755 docs/assets/logo.png create mode 100755 docs/assets/node-view-layer.png create mode 100755 docs/build.sh create mode 100755 docs/css/main.scss create mode 100644 docs/guide/1-introduction.md create mode 100644 docs/guide/2-custom-nodes.md create mode 100644 docs/guide/3-asynchronous-display.md create mode 100644 docs/guide/4-making-the-most-of-asdk.md create mode 100644 docs/guide/5-under-the-hood.md create mode 100644 docs/index.md diff --git a/docs/CNAME b/docs/CNAME new file mode 100644 index 0000000000..a295f461e5 --- /dev/null +++ b/docs/CNAME @@ -0,0 +1,2 @@ +asyncdisplaykit.org + diff --git a/docs/LICENSE.md b/docs/LICENSE.md new file mode 100644 index 0000000000..4bb498ec63 --- /dev/null +++ b/docs/LICENSE.md @@ -0,0 +1,420 @@ +--- +layout: page +title: License +permalink: /license/ +--- + +AsyncDisplayKit is free software under the
BSD +license. + +Code examples and sample +projects are licensed as follows: + + This file provided by Facebook is for non-commercial testing and evaluation + purposes only. Facebook reserves all rights not expressly granted. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +All other AsyncDisplayKit documentation is licensed CC-BY-4.0. + + Attribution 4.0 International + + ======================================================================= + + Creative Commons Corporation ("Creative Commons") is not a law firm and + does not provide legal services or legal advice. Distribution of + Creative Commons public licenses does not create a lawyer-client or + other relationship. Creative Commons makes its licenses and related + information available on an "as-is" basis. Creative Commons gives no + warranties regarding its licenses, any material licensed under their + terms and conditions, or any related information. Creative Commons + disclaims all liability for damages resulting from their use to the + fullest extent possible. + + Using Creative Commons Public Licenses + + Creative Commons public licenses provide a standard set of terms and + conditions that creators and other rights holders may use to share + original works of authorship and other material subject to copyright + and certain other rights specified in the public license below. The + following considerations are for informational purposes only, are not + exhaustive, and do not form part of our licenses. + + Considerations for licensors: Our public licenses are + intended for use by those authorized to give the public + permission to use material in ways otherwise restricted by + copyright and certain other rights. Our licenses are + irrevocable. Licensors should read and understand the terms + and conditions of the license they choose before applying it. + Licensors should also secure all rights necessary before + applying our licenses so that the public can reuse the + material as expected. Licensors should clearly mark any + material not subject to the license. This includes other CC- + licensed material, or material used under an exception or + limitation to copyright. More considerations for licensors: + wiki.creativecommons.org/Considerations_for_licensors + + Considerations for the public: By using one of our public + licenses, a licensor grants the public permission to use the + licensed material under specified terms and conditions. If + the licensor's permission is not necessary for any reason--for + example, because of any applicable exception or limitation to + copyright--then that use is not regulated by the license. Our + licenses grant only permissions under copyright and certain + other rights that a licensor has authority to grant. Use of + the licensed material may still be restricted for other + reasons, including because others have copyright or other + rights in the material. A licensor may make special requests, + such as asking that all changes be marked or described. + Although not required by our licenses, you are encouraged to + respect those requests where reasonable. More_considerations + for the public: + wiki.creativecommons.org/Considerations_for_licensees + + ======================================================================= + + Creative Commons Attribution 4.0 International Public License + + By exercising the Licensed Rights (defined below), You accept and agree + to be bound by the terms and conditions of this Creative Commons + Attribution 4.0 International Public License ("Public License"). To the + extent this Public License may be interpreted as a contract, You are + granted the Licensed Rights in consideration of Your acceptance of + these terms and conditions, and the Licensor grants You such rights in + consideration of benefits the Licensor receives from making the + Licensed Material available under these terms and conditions. + + + Section 1 -- Definitions. + + a. Adapted Material means material subject to Copyright and Similar + Rights that is derived from or based upon the Licensed Material + and in which the Licensed Material is translated, altered, + arranged, transformed, or otherwise modified in a manner requiring + permission under the Copyright and Similar Rights held by the + Licensor. For purposes of this Public License, where the Licensed + Material is a musical work, performance, or sound recording, + Adapted Material is always produced where the Licensed Material is + synched in timed relation with a moving image. + + b. Adapter's License means the license You apply to Your Copyright + and Similar Rights in Your contributions to Adapted Material in + accordance with the terms and conditions of this Public License. + + c. Copyright and Similar Rights means copyright and/or similar rights + closely related to copyright including, without limitation, + performance, broadcast, sound recording, and Sui Generis Database + Rights, without regard to how the rights are labeled or + categorized. For purposes of this Public License, the rights + specified in Section 2(b)(1)-(2) are not Copyright and Similar + Rights. + + d. Effective Technological Measures means those measures that, in the + absence of proper authority, may not be circumvented under laws + fulfilling obligations under Article 11 of the WIPO Copyright + Treaty adopted on December 20, 1996, and/or similar international + agreements. + + e. Exceptions and Limitations means fair use, fair dealing, and/or + any other exception or limitation to Copyright and Similar Rights + that applies to Your use of the Licensed Material. + + f. Licensed Material means the artistic or literary work, database, + or other material to which the Licensor applied this Public + License. + + g. Licensed Rights means the rights granted to You subject to the + terms and conditions of this Public License, which are limited to + all Copyright and Similar Rights that apply to Your use of the + Licensed Material and that the Licensor has authority to license. + + h. Licensor means the individual(s) or entity(ies) granting rights + under this Public License. + + i. Share means to provide material to the public by any means or + process that requires permission under the Licensed Rights, such + as reproduction, public display, public performance, distribution, + dissemination, communication, or importation, and to make material + available to the public including in ways that members of the + public may access the material from a place and at a time + individually chosen by them. + + j. Sui Generis Database Rights means rights other than copyright + resulting from Directive 96/9/EC of the European Parliament and of + the Council of 11 March 1996 on the legal protection of databases, + as amended and/or succeeded, as well as other essentially + equivalent rights anywhere in the world. + + k. You means the individual or entity exercising the Licensed Rights + under this Public License. Your has a corresponding meaning. + + + Section 2 -- Scope. + + a. License grant. + + 1. Subject to the terms and conditions of this Public License, + the Licensor hereby grants You a worldwide, royalty-free, + non-sublicensable, non-exclusive, irrevocable license to + exercise the Licensed Rights in the Licensed Material to: + + a. reproduce and Share the Licensed Material, in whole or + in part; and + + b. produce, reproduce, and Share Adapted Material. + + 2. Exceptions and Limitations. For the avoidance of doubt, where + Exceptions and Limitations apply to Your use, this Public + License does not apply, and You do not need to comply with + its terms and conditions. + + 3. Term. The term of this Public License is specified in Section + 6(a). + + 4. Media and formats; technical modifications allowed. The + Licensor authorizes You to exercise the Licensed Rights in + all media and formats whether now known or hereafter created, + and to make technical modifications necessary to do so. The + Licensor waives and/or agrees not to assert any right or + authority to forbid You from making technical modifications + necessary to exercise the Licensed Rights, including + technical modifications necessary to circumvent Effective + Technological Measures. For purposes of this Public License, + simply making modifications authorized by this Section 2(a) + (4) never produces Adapted Material. + + 5. Downstream recipients. + + a. Offer from the Licensor -- Licensed Material. Every + recipient of the Licensed Material automatically + receives an offer from the Licensor to exercise the + Licensed Rights under the terms and conditions of this + Public License. + + b. No downstream restrictions. You may not offer or impose + any additional or different terms or conditions on, or + apply any Effective Technological Measures to, the + Licensed Material if doing so restricts exercise of the + Licensed Rights by any recipient of the Licensed + Material. + + 6. No endorsement. Nothing in this Public License constitutes or + may be construed as permission to assert or imply that You + are, or that Your use of the Licensed Material is, connected + with, or sponsored, endorsed, or granted official status by, + the Licensor or others designated to receive attribution as + provided in Section 3(a)(1)(A)(i). + + b. Other rights. + + 1. Moral rights, such as the right of integrity, are not + licensed under this Public License, nor are publicity, + privacy, and/or other similar personality rights; however, to + the extent possible, the Licensor waives and/or agrees not to + assert any such rights held by the Licensor to the limited + extent necessary to allow You to exercise the Licensed + Rights, but not otherwise. + + 2. Patent and trademark rights are not licensed under this + Public License. + + 3. To the extent possible, the Licensor waives any right to + collect royalties from You for the exercise of the Licensed + Rights, whether directly or through a collecting society + under any voluntary or waivable statutory or compulsory + licensing scheme. In all other cases the Licensor expressly + reserves any right to collect such royalties. + + + Section 3 -- License Conditions. + + Your exercise of the Licensed Rights is expressly made subject to the + following conditions. + + a. Attribution. + + 1. If You Share the Licensed Material (including in modified + form), You must: + + a. retain the following if it is supplied by the Licensor + with the Licensed Material: + + i. identification of the creator(s) of the Licensed + Material and any others designated to receive + attribution, in any reasonable manner requested by + the Licensor (including by pseudonym if + designated); + + ii. a copyright notice; + + iii. a notice that refers to this Public License; + + iv. a notice that refers to the disclaimer of + warranties; + + v. a URI or hyperlink to the Licensed Material to the + extent reasonably practicable; + + b. indicate if You modified the Licensed Material and + retain an indication of any previous modifications; and + + c. indicate the Licensed Material is licensed under this + Public License, and include the text of, or the URI or + hyperlink to, this Public License. + + 2. You may satisfy the conditions in Section 3(a)(1) in any + reasonable manner based on the medium, means, and context in + which You Share the Licensed Material. For example, it may be + reasonable to satisfy the conditions by providing a URI or + hyperlink to a resource that includes the required + information. + + 3. If requested by the Licensor, You must remove any of the + information required by Section 3(a)(1)(A) to the extent + reasonably practicable. + + 4. If You Share Adapted Material You produce, the Adapter's + License You apply must not prevent recipients of the Adapted + Material from complying with this Public License. + + + Section 4 -- Sui Generis Database Rights. + + Where the Licensed Rights include Sui Generis Database Rights that + apply to Your use of the Licensed Material: + + a. for the avoidance of doubt, Section 2(a)(1) grants You the right + to extract, reuse, reproduce, and Share all or a substantial + portion of the contents of the database; + + b. if You include all or a substantial portion of the database + contents in a database in which You have Sui Generis Database + Rights, then the database in which You have Sui Generis Database + Rights (but not its individual contents) is Adapted Material; and + + c. You must comply with the conditions in Section 3(a) if You Share + all or a substantial portion of the contents of the database. + + For the avoidance of doubt, this Section 4 supplements and does not + replace Your obligations under this Public License where the Licensed + Rights include other Copyright and Similar Rights. + + + Section 5 -- Disclaimer of Warranties and Limitation of Liability. + + a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE + EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS + AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF + ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS, + IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION, + WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR + PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS, + ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT + KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT + ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU. + + b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE + TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION, + NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT, + INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES, + COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR + USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN + ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR + DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR + IN PART, THIS LIMITATION MAY NOT APPLY TO YOU. + + c. The disclaimer of warranties and limitation of liability provided + above shall be interpreted in a manner that, to the extent + possible, most closely approximates an absolute disclaimer and + waiver of all liability. + + + Section 6 -- Term and Termination. + + a. This Public License applies for the term of the Copyright and + Similar Rights licensed here. However, if You fail to comply with + this Public License, then Your rights under this Public License + terminate automatically. + + b. Where Your right to use the Licensed Material has terminated under + Section 6(a), it reinstates: + + 1. automatically as of the date the violation is cured, provided + it is cured within 30 days of Your discovery of the + violation; or + + 2. upon express reinstatement by the Licensor. + + For the avoidance of doubt, this Section 6(b) does not affect any + right the Licensor may have to seek remedies for Your violations + of this Public License. + + c. For the avoidance of doubt, the Licensor may also offer the + Licensed Material under separate terms or conditions or stop + distributing the Licensed Material at any time; however, doing so + will not terminate this Public License. + + d. Sections 1, 5, 6, 7, and 8 survive termination of this Public + License. + + + Section 7 -- Other Terms and Conditions. + + a. The Licensor shall not be bound by any additional or different + terms or conditions communicated by You unless expressly agreed. + + b. Any arrangements, understandings, or agreements regarding the + Licensed Material not stated herein are separate from and + independent of the terms and conditions of this Public License. + + + Section 8 -- Interpretation. + + a. For the avoidance of doubt, this Public License does not, and + shall not be interpreted to, reduce, limit, restrict, or impose + conditions on any use of the Licensed Material that could lawfully + be made without permission under this Public License. + + b. To the extent possible, if any provision of this Public License is + deemed unenforceable, it shall be automatically reformed to the + minimum extent necessary to make it enforceable. If the provision + cannot be reformed, it shall be severed from this Public License + without affecting the enforceability of the remaining terms and + conditions. + + c. No term or condition of this Public License will be waived and no + failure to comply consented to unless expressly agreed to by the + Licensor. + + d. Nothing in this Public License constitutes or may be interpreted + as a limitation upon, or waiver of, any privileges and immunities + that apply to the Licensor or You, including from the legal + processes of any jurisdiction or authority. + + + ======================================================================= + + Creative Commons is not a party to its public licenses. + Notwithstanding, Creative Commons may elect to apply one of its public + licenses to material it publishes and in those instances will be + considered the "Licensor." Except for the limited purpose of indicating + that material is shared under a Creative Commons public license or as + otherwise permitted by the Creative Commons policies published at + creativecommons.org/policies, Creative Commons does not authorize the + use of the trademark "Creative Commons" or any other trademark or logo + of Creative Commons without its prior written consent including, + without limitation, in connection with any unauthorized modifications + to any of its public licenses or any other arrangements, + understandings, or agreements concerning use of licensed material. For + the avoidance of doubt, this paragraph does not form part of the public + licenses. + + Creative Commons may be contacted at creativecommons.org. diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 0000000000..05980d3818 --- /dev/null +++ b/docs/README.md @@ -0,0 +1,9 @@ +# Documentation + +## Building + +You need Jekyll and appledoc. See `build.sh`. + +## License + +See LICENSE.md. diff --git a/docs/_config.yml b/docs/_config.yml new file mode 100644 index 0000000000..0d5f309f67 --- /dev/null +++ b/docs/_config.yml @@ -0,0 +1,13 @@ +# Site settings +title: AsyncDisplayKit +description: Smooth asynchronous user interfaces for iOS apps. +baseurl: "" +url: "http://asyncdisplaykit.org" + +# Build settings +highlighter: pygments +markdown: redcarpet + +exclude: +- README.md +- build.sh diff --git a/docs/_includes/footer.html b/docs/_includes/footer.html new file mode 100644 index 0000000000..2714963def --- /dev/null +++ b/docs/_includes/footer.html @@ -0,0 +1,18 @@ +

+ +
+ + +
+ +
diff --git a/docs/_includes/head.html b/docs/_includes/head.html new file mode 100644 index 0000000000..a9e7efbdea --- /dev/null +++ b/docs/_includes/head.html @@ -0,0 +1,24 @@ + + + + + + + + + + + + {% if page.title %}{{ page.title }} — {% endif %}AsyncDisplayKit + + + + + + + diff --git a/docs/_includes/header.html b/docs/_includes/header.html new file mode 100644 index 0000000000..aebb67cdf1 --- /dev/null +++ b/docs/_includes/header.html @@ -0,0 +1,25 @@ + diff --git a/docs/_layouts/default.html b/docs/_layouts/default.html new file mode 100644 index 0000000000..bdf5a388da --- /dev/null +++ b/docs/_layouts/default.html @@ -0,0 +1,20 @@ + + + + {% include head.html %} + + + + {% include header.html %} + +
+
+ {{ content }} +
+
+ + {% include footer.html %} + + + + diff --git a/docs/_layouts/docs.html b/docs/_layouts/docs.html new file mode 100644 index 0000000000..65c07040aa --- /dev/null +++ b/docs/_layouts/docs.html @@ -0,0 +1,27 @@ +--- +layout: default +sectionid: docs +--- +
+ +
+

+ {{ page.title }} + [edit] +

+
+ +
+ {{ content }} +
+ +
+ {% if page.prev %} + ← prev + {% endif %} + {% if page.next %} + next → + {% endif %} +
+ +
diff --git a/docs/_layouts/page.html b/docs/_layouts/page.html new file mode 100644 index 0000000000..8e7ccf7a15 --- /dev/null +++ b/docs/_layouts/page.html @@ -0,0 +1,16 @@ +--- +layout: default +--- +
+ + {% if page.shouldDisplayTitle %} +
+

{{ page.title }}

+
+ {% endif %} + +
+ {{ content }} +
+ +
diff --git a/docs/_layouts/post.html b/docs/_layouts/post.html new file mode 100644 index 0000000000..675596fb1c --- /dev/null +++ b/docs/_layouts/post.html @@ -0,0 +1,15 @@ +--- +layout: default +--- +
+ +
+

{{ page.title }}

+ +
+ +
+ {{ content }} +
+ +
diff --git a/docs/_sass/_base.scss b/docs/_sass/_base.scss new file mode 100644 index 0000000000..7d353be258 --- /dev/null +++ b/docs/_sass/_base.scss @@ -0,0 +1,205 @@ +/** + * Reset some basic elements + */ +body, h1, h2, h3, h4, h5, h6, +p, blockquote, pre, hr, +dl, dd, ol, ul, figure { + margin: 0; + padding: 0; +} + + + +/** + * Basic styling + */ +body { + font-family: $base-font-family; + font-size: $base-font-size; + line-height: $base-line-height; + font-weight: 300; + color: $text-color; + background-color: $background-color; + -webkit-text-size-adjust: 100%; +} + + + +/** + * Set `margin-bottom` to maintain vertical rhythm + */ +h1, h2, h3, h4, h5, h6, +p, blockquote, pre, +ul, ol, dl, figure, +%vertical-rhythm { + margin-bottom: $spacing-unit / 2; +} + + + +/** + * Images + */ +img { + max-width: 100%; + vertical-align: middle; +} + + + +/** + * Figures + */ +figure > img { + display: block; +} + +figcaption { + font-size: $small-font-size; +} + + + +/** + * Lists + */ +ul, ol { + margin-left: $spacing-unit; +} + +li { + > ul, + > ol { + margin-bottom: 0; + } +} + + + +/** + * Headings + */ +h1, h2, h3, h4, h5, h6 { + font-weight: 300; +} + + + +/** + * Links + */ +a { + color: $brand-color; + text-decoration: none; + + &:visited { + color: darken($brand-color, 15%); + } + + &:hover { + color: $text-color; + text-decoration: underline; + } +} + + + +/** + * Blockquotes + */ +blockquote { + color: $grey-color; + border-left: 4px solid $grey-color-light; + padding-left: $spacing-unit / 2; + font-size: 18px; + letter-spacing: -1px; + font-style: italic; + + > :last-child { + margin-bottom: 0; + } +} + + + +/** + * Code formatting + */ +pre, +code { + font-family: Monaco, monospace; + font-size: 14px; + border: 1px solid #afe4ff; + border-radius: 3px; + background-color: #fafdff; +} + +code { + padding: 1px 5px; +} + +pre { + padding: 8px 12px; + overflow-x: scroll; + + > code { + border: 0; + padding-right: 0; + padding-left: 0; + } +} + + + +/** + * Wrapper + */ +.wrapper { + max-width: -webkit-calc(800px - (#{$spacing-unit} * 2)); + max-width: calc(800px - (#{$spacing-unit} * 2)); + margin-right: auto; + margin-left: auto; + padding-right: $spacing-unit; + padding-left: $spacing-unit; + @extend %clearfix; + + @include media-query($on-laptop) { + max-width: -webkit-calc(800px - (#{$spacing-unit})); + max-width: calc(800px - (#{$spacing-unit})); + padding-right: $spacing-unit / 2; + padding-left: $spacing-unit / 2; + } +} + + + +/** + * Clearfix + */ +%clearfix { + + &:after { + content: ""; + display: table; + clear: both; + } +} + + + +/** + * Icons + */ +.icon { + + > svg { + display: inline-block; + width: 16px; + height: 16px; + vertical-align: middle; + + path { + fill: $grey-color; + } + } +} diff --git a/docs/_sass/_layout.scss b/docs/_sass/_layout.scss new file mode 100644 index 0000000000..2eb740fa67 --- /dev/null +++ b/docs/_sass/_layout.scss @@ -0,0 +1,265 @@ +/** + * Site header + */ +.site-header { + border-top: 5px solid $grey-color-dark; + border-bottom: 1px solid $grey-color-light; + min-height: 56px; + background-color: #f8f8f8; + + // Positioning context for the mobile navigation icon + position: relative; +} + +.site-title { + font-size: 26px; + line-height: 56px; + letter-spacing: -1px; + margin-bottom: 0; + float: left; + + &, + &:visited { + color: $grey-color-dark; + } + &:hover { + text-decoration: none; + } +} + +.site-nav { + float: right; + line-height: 56px; + + .menu-icon { + display: none; + } + + .page-link { + color: $grey-color; + line-height: $base-line-height; + + // Gaps between nav items, but not on the first one + &:not(:first-child) { + margin-left: 20px; + } + + &:hover { + color: $text-color; + } + } + + .page-link-active { + color: $text-color; + } + + @include media-query($on-palm) { + position: absolute; + top: 9px; + right: 30px; + background-color: $background-color; + border: 1px solid $grey-color-light; + border-radius: 5px; + text-align: right; + + .menu-icon { + display: block; + float: right; + width: 36px; + height: 26px; + line-height: 0; + padding-top: 10px; + text-align: center; + + > svg { + width: 18px; + height: 15px; + + path { + fill: $grey-color-dark; + } + } + } + + .trigger { + clear: both; + display: none; + } + + &:hover .trigger { + display: block; + padding-bottom: 5px; + } + + .page-link { + display: block; + padding: 5px 10px; + } + } +} + + + +/** + * Site footer + */ +.site-footer { + border-top: 1px solid $grey-color-light; + padding: $spacing-unit 0; +} + +.footer-heading { + font-size: 18px; + margin-bottom: $spacing-unit / 2; +} + +.contact-list, +.social-media-list { + list-style: none; + margin-left: 0; +} + +.footer-col-wrapper { + font-size: 11px; + color: $grey-color; + margin-left: -$spacing-unit / 2; + @extend %clearfix; +} + +.footer-col { + float: left; + margin-bottom: $spacing-unit / 2; + padding-left: $spacing-unit / 2; +} + +.footer-col-left { + width: -webkit-calc(50% - (#{$spacing-unit} / 2)); + width: calc(50% - (#{$spacing-unit} / 2)); +} + +.footer-col-right { + text-align: right; + width: -webkit-calc(50% - (#{$spacing-unit} / 2)); + width: calc(50% - (#{$spacing-unit} / 2)); +} + +@include media-query($on-laptop) { + .footer-col-left { + width: -webkit-calc(50% - (#{$spacing-unit} / 2)); + width: calc(50% - (#{$spacing-unit} / 2)); + } + + .footer-col-right { + width: -webkit-calc(100% - (#{$spacing-unit} / 2)); + width: calc(100% - (#{$spacing-unit} / 2)); + } +} + +@include media-query($on-palm) { + .footer-col { + float: none; + width: -webkit-calc(100% - (#{$spacing-unit} / 2)); + width: calc(100% - (#{$spacing-unit} / 2)); + } +} + + + +/** + * Page content + */ +.page-content { + padding: $spacing-unit 0; + background-color: white; +} + +.page-heading { + font-size: 20px; +} + +.post-list { + margin-left: 0; + list-style: none; + + > li { + margin-bottom: $spacing-unit; + } +} + +.post-meta { + font-size: $small-font-size; + color: $grey-color; +} + +.post-link { + display: block; + font-size: 24px; +} + + + +/** + * Posts + */ +.post-header { + margin-bottom: $spacing-unit; +} + +.post-title { + font-size: 42px; + letter-spacing: -1px; + line-height: 1; + + @include media-query($on-laptop) { + font-size: 36px; + } + + .edit-page-link { + font-size: 18px; + } +} + +.post-content { + margin-bottom: $spacing-unit; + + h2 { + font-size: 32px; + + @include media-query($on-laptop) { + font-size: 28px; + } + } + + h3 { + font-size: 26px; + + @include media-query($on-laptop) { + font-size: 22px; + } + } + + h4 { + font-size: 20px; + + @include media-query($on-laptop) { + font-size: 18px; + } + } +} + + + +/** + * Docs + */ +.docs-prevnext { + @extend %clearfix; +} + +.docs-prev { + float: left; +} + +.docs-next { + float: right; +} diff --git a/docs/_sass/_syntax-highlighting.scss b/docs/_sass/_syntax-highlighting.scss new file mode 100644 index 0000000000..3758fdb458 --- /dev/null +++ b/docs/_sass/_syntax-highlighting.scss @@ -0,0 +1,76 @@ +/** + * Syntax highlighting styles + */ + +/* not official Xcode colors, but looks better on the web */ +$xc-black: black; +$xc-green: #008d14; +$xc-red: #b72748; +$xc-blue: #103ffb; +$xc-turquoise: #3a95ba; + +.highlight { + background: #fff; + @extend %vertical-rhythm; + + .c { color: $xc-green; font-style: italic } // Comment + .err { color: #a61717; background-color: #e3d2d2 } // Error + .k { color: $xc-blue} // Keyword + .o { } // Operator + .cm { color: $xc-green; font-style: italic } // Comment.Multiline + .cp { color: $xc-red} // Comment.Preproc + .c1 { color: $xc-green; font-style: italic } // Comment.Single + .cs { color: $xc-green; font-weight: bold; font-style: italic } // Comment.Special + .gd { color: #000; background-color: #fdd } // Generic.Deleted + .gd .x { color: #000; background-color: #faa } // Generic.Deleted.Specific + .ge { font-style: italic } // Generic.Emph + .gr { color: #a00 } // Generic.Error + .gh { color: #999 } // Generic.Heading + .gi { color: #000; background-color: #dfd } // Generic.Inserted + .gi .x { color: #000; background-color: #afa } // Generic.Inserted.Specific + .go { color: #888 } // Generic.Output + .gp { color: #555 } // Generic.Prompt + .gs { font-weight: bold } // Generic.Strong + .gu { color: #aaa } // Generic.Subheading + .gt { color: #a00 } // Generic.Traceback + .kc { color: orange} // Keyword.Constant + .kd { color: orange} // Keyword.Declaration + .kp { color: $xc-green} // Keyword.Pseudo + .kr { color: $xc-green} // Keyword.Reserved + .kt { color: $xc-blue} // Keyword.Type + .m { color: orange } // Literal.Number + .s { color: $xc-red } // Literal.String + .na { color: orange } // Name.Attribute + .nb { color: $xc-blue } // Name.Builtin + .nc { color: $xc-turquoise } // Name.Class + .no { color: orange } // Name.Constant + .ni { color: orange } // Name.Entity + .ne { color: orange } // Name.Exception + .nf { } // Name.Function + .nn { color: orange } // Name.Namespace + .nt { color: orange } // Name.Tag + .nv { } // Name.Variable + .ow { } // Operator.Word + .w { color: #bbb } // Text.Whitespace + .mf {} // Literal.Number.Float + .mh { color: $xc-black } // Literal.Number.Hex + .mi { color: $xc-black } // Literal.Number.Integer + .mo { color: $xc-black } // Literal.Number.Oct + .il { color: $xc-black } // Literal.Number.Integer.Long + .sb { color: #d14 } // Literal.String.Backtick + .sc { color: #d14 } // Literal.String.Char + .sd { color: #d14 } // Literal.String.Doc + .s2 { color: #d14 } // Literal.String.Double + .se { color: #d14 } // Literal.String.Escape + .sh { color: #d14 } // Literal.String.Heredoc + .si { color: #d14 } // Literal.String.Interpol + .sx { color: #d14 } // Literal.String.Other + .sr { color: orange } // Literal.String.Regex + .s1 { color: $xc-red } // Literal.String.Single + .ss { color: $xc-red } // Literal.String.Symbol + .bp { color: $xc-turquoise } // Name.Builtin.Pseudo + .vc { color: $xc-turquoise } // Name.Variable.Class + .vg { color: $xc-black } // Name.Variable.Global + .vi { color: orange } // Name.Variable.Instance + .nl { color: $xc-turquoise } +} diff --git a/docs/assets/guide/1-shuffle-crop.png b/docs/assets/guide/1-shuffle-crop.png new file mode 100644 index 0000000000000000000000000000000000000000..d1e0a83b0c3c23ee7ae938f88dbc1bebd1f27246 GIT binary patch literal 1016 zcmeAS@N?(olHy`uVBq!ia0y~yVB7>`>u|6ENrnvD*+5dT#5JNMI6tkVJh3R1p&&0k zxu~=_!=cpkGXn$jB2O2`kcwMxZ~J!mRm&Xs_};iY&1Un1je<(9C!d&UW^G$>v%+)X zo+C?KIyKyq)KW7hi5zu0>2@efY{{~WBTj)zulO`CP2ug%G@ALSa$d2xeewC3&(F=h zy>n-2{J!~CbFV+Q{5oe@{_{Eiuc&(-O5tjCQr!KE{qwFfRb{JYC+uC9R=Mcq@-utN zcG_)@n}0LTx>xpd@g$X4k4ygp76!avtYg%2`1-qM(aJfN%jVpSo13uH>g1FwI_fiX zJ1OZfs&pZJ}bs zX11v4WL$hKC0e^h&GWAcX&igRove_L54T-D0R z?*7rcvtHiH`thIM-j6RfuH@X7|9uw7*u-Nz72ov^UAo4mA9rAi=7%?uXXbLd_Z=y$ z{&t{OdUAcZGqX-4Q)%gjlFS_KsR;*}W*Ddc**IPA;4qzs&OJFbe=P29D_D5l*(fE*@9$rO;gu28wiO2Vj*D^`)K>ARSQZ?3tte@vxtv$}(fnz@e!1 zavq)oD}y)W%>_B&Qv8OhQlH4r&wAzg;vVkME-0f`@ZX99t7%_)q5S zS)dRoIl>YeG&!QCJx^e&QGp3T(=JTt-{Lyf_xt`VW4m~78z@J6y85}Sb4q9e0NQ!% A6951J literal 0 HcmV?d00001 diff --git a/docs/assets/guide/1-shuffle.png b/docs/assets/guide/1-shuffle.png new file mode 100644 index 0000000000000000000000000000000000000000..9188eebf8ae9edd78fadd80b1a8f994e116c88e4 GIT binary patch literal 19288 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 literal 0 HcmV?d00001 diff --git a/docs/assets/logo-square.png b/docs/assets/logo-square.png new file mode 100755 index 0000000000000000000000000000000000000000..82ad66c69ecdd8626cdd380e5c536dbcaeb0a0fc GIT binary patch literal 66422 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

Axt>VUn+{%`lVxh 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 literal 0 HcmV?d00001 diff --git a/docs/assets/logo.png b/docs/assets/logo.png new file mode 100755 index 0000000000000000000000000000000000000000..dce1ebc95066e56bf72c591027b7776b767a5786 GIT binary patch literal 105684 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

AgH(i{EZ2lp^1>P->`lX~`! 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 literal 0 HcmV?d00001 diff --git a/docs/build.sh b/docs/build.sh new file mode 100755 index 0000000000..c532bb0d6b --- /dev/null +++ b/docs/build.sh @@ -0,0 +1,33 @@ +#!/bin/sh +set -e + +HEADERS=`ls ../AsyncDisplayKit/*.h ../AsyncDisplayKit/Details/ASRangeController.h ../AsyncDisplayKit/Layout/*.h` + +rm -rf htdocs appledoc + +jekyll build --destination htdocs + +appledoc \ + --no-create-docset \ + --create-html \ + --exit-threshold 2 \ + --no-repeat-first-par \ + --no-merge-categories \ + --explicit-crossref \ + --warn-missing-output-path \ + --warn-missing-company-id \ + --warn-undocumented-object \ + --warn-undocumented-member \ + --warn-empty-description \ + --warn-unknown-directive \ + --warn-invalid-crossref \ + --warn-missing-arg \ + --project-name AsyncDisplayKit \ + --project-company Facebook \ + --company-id "com.facebook" \ + --output appledoc \ + $HEADERS + +mv appledoc/html htdocs/appledoc + +rmdir appledoc diff --git a/docs/css/main.scss b/docs/css/main.scss new file mode 100755 index 0000000000..4417ff0713 --- /dev/null +++ b/docs/css/main.scss @@ -0,0 +1,49 @@ +--- +# Only the main Sass file needs front matter (the dashes are enough) +--- +@charset "utf-8"; + + + +// Our variables +$base-font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; +$base-font-size: 16px; +$small-font-size: $base-font-size * 0.875; +$base-line-height: 1.5; + +$spacing-unit: 30px; + +$text-color: #111; +$background-color: #f8f8f8; +$brand-color: #21b6ff; + +$grey-color: #828282; +$grey-color-light: lighten($grey-color, 40%); +$grey-color-dark: darken($grey-color, 25%); + +$on-palm: 600px; +$on-laptop: 800px; + + + +// Using media queries with like this: +// @include media-query($palm) { +// .wrapper { +// padding-right: $spacing-unit / 2; +// padding-left: $spacing-unit / 2; +// } +// } +@mixin media-query($device) { + @media screen and (max-width: $device) { + @content; + } +} + + + +// Import partials from `sass_dir` (defaults to `_sass`) +@import + "base", + "layout", + "syntax-highlighting" +; diff --git a/docs/guide/1-introduction.md b/docs/guide/1-introduction.md new file mode 100644 index 0000000000..d923c0a215 --- /dev/null +++ b/docs/guide/1-introduction.md @@ -0,0 +1,150 @@ +--- +layout: docs +title: Getting started +permalink: /guide/ +next: guide/2/ +--- + +## Concepts + +AsyncDisplayKit's basic unit is the *node*. ASDisplayNode is an abstraction +over UIView, which in turn is an abstraction over CALayer. Unlike views, which +can only be used on the main thread, nodes are thread-safe: you can +instantiate and configure entire hierarchies of them in parallel on background +threads. + +To keep its user interface smooth and responsive, your app should render at 60 +frames per second — the gold standard on iOS. This means the main thread +has one-sixtieth of a second to push each frame. That's 16 milliseconds to +execute all layout and drawing code! And because of system overhead, your code +usually has less than ten milliseconds to run before it causes a frame drop. + +AsyncDisplayKit lets you move image decoding, text sizing and rendering, and +other expensive UI operations off the main thread. It has other tricks up its +sleeve too... but we'll get to that later. :] + +## Nodes as drop-in view replacements + +If you're used to working with views, you already know how to use nodes. The +node API is similar to UIView's, with some additional conveniences — for +example, you can access common CALayer properties directly. To add a node to +an existing view or layer hierarchy, use its `node.view` or `node.layer`. + +AsyncDisplayKit's core components include: + +* *ASDisplayNode*. Counterpart to UIView — subclass to make custom nodes. +* *ASControlNode*. Analogous to UIControl — subclass to make buttons. +* *ASImageNode*. Like UIImageView — decodes images asynchronously. +* *ASTextNode*. Like UITextView — built on TextKit with full-featured + rich text support. +* *ASTableView* and *ASCollectionView*. UITableView and UICollectionView + subclasses that support nodes. + +You can use these as drop-in replacements for their UIKit counterparts. While +ASDK works most effectively with fully node-based hierarchies, even replacing +individual views with nodes can improve performance. + +Let's look at an example. + +We'll start out by using nodes synchronously on the main thread — the +same way you already use views. This code is a familiar sight in custom view +controller `-loadView` implementations: + +```objective-c +_imageView = [[UIImageView alloc] init]; +_imageView.image = [UIImage imageNamed:@"hello"]; +_imageView.frame = CGRectMake(10.0f, 10.0f, 40.0f, 40.0f); +[self.view addSubview:_imageView]; +``` + +We can replace it with the following node-based code: + +```objective-c +_imageNode = [[ASImageNode alloc] init]; +_imageNode.backgroundColor = [UIColor lightGrayColor]; +_imageNode.image = [UIImage imageNamed:@"hello"]; +_imageNode.frame = CGRectMake(10.0f, 10.0f, 40.0f, 40.0f); +[self.view addSubview:_imageNode.view]; +``` + +This doesn't take advantage of ASDK's asynchronous sizing and layout +functionality, but it's already an improvement. The first block of code +synchronously decodes `hello.png` on the main thread; the second starts +decoding the image on a background thread, possibly on a different CPU core. + +(Note that we're setting a placeholder background colour on the node, "holding +its place" onscreen until the real content appears. This works well with +images but less so with text — people expect text to appear instantly, +with images loading in after a slight delay. We'll discuss techniques to +improve this later on.) + +## Button nodes + +ASImageNode and ASTextNode both inherit from ASControlNode, so you can use them +as buttons. Let's say we're making a music player and we want to add a +(non-skeuomorphic, iOS 7-style) shuffle button: + +[![shuffle]({{ site.baseurl }}/assets/guide/1-shuffle-crop.png)]({{ site.baseurl }}/assets/guide/1-shuffle.png) + +Our view controller will look something like this: + +```objective-c +- (void)viewDidLoad +{ + [super viewDidLoad]; + + // attribute a string + NSDictionary *attrs = @{ + NSFontAttributeName: [UIFont systemFontOfSize:12.0f], + NSForegroundColorAttributeName: [UIColor redColor], + }; + NSAttributedString *string = [[NSAttributedString alloc] initWithString:@"shuffle" + attributes:attrs]; + + // create the node + _shuffleNode = [[ASTextNode alloc] init]; + _shuffleNode.attributedString = string; + + // configure the button + _shuffleNode.userInteractionEnabled = YES; // opt into touch handling + [_shuffleNode addTarget:self + action:@selector(buttonTapped:) + forControlEvents:ASControlNodeEventTouchUpInside]; + + // size all the things + CGRect b = self.view.bounds; // convenience + CGSize size = [_shuffleNode measure:CGSizeMake(b.size.width, FLT_MAX)]; + CGPoint origin = CGPointMake(roundf( (b.size.width - size.width) / 2.0f ), + roundf( (b.size.height - size.height) / 2.0f )); + _shuffleNode.frame = (CGRect){ origin, size }; + + // add to our view + [self.view addSubview:_shuffleNode.view]; +} + +- (void)buttonTapped:(id)sender +{ + NSLog(@"tapped!"); +} +``` + +This works as you would expect. Unfortunately, this button is only 14½ +points tall — nowhere near the standard 44×44 minimum tap target +size — and it's very difficult to tap. We could solve this by +subclassing the text node and overriding `-hitTest:withEvent:`. We could even +force the text view to have a minimum height during layout. But wouldn't it be +nice if there were a more elegant way? + +```objective-c + // size all the things + /* ... */ + + // make the tap target taller + CGFloat extendY = roundf( (44.0f - size.height) / 2.0f ); + _shuffleNode.hitTestSlop = UIEdgeInsetsMake(-extendY, 0.0f, -extendY, 0.0f); +``` + +Et voilà! *Hit-test slops* work on all nodes, and are a nice example of what +this new abstraction enables. + +Next up, making your own nodes! diff --git a/docs/guide/2-custom-nodes.md b/docs/guide/2-custom-nodes.md new file mode 100644 index 0000000000..6d67ed3a05 --- /dev/null +++ b/docs/guide/2-custom-nodes.md @@ -0,0 +1,211 @@ +--- +layout: docs +title: Custom nodes +permalink: /guide/2/ +prev: guide/ +next: guide/3/ +--- + +## View hierarchies + +Sizing and layout of custom view hierarchies are typically done all at once on +the main thread. For example, a custom UIView that minimally encloses a text +view and an image view might look like this: + +```objective-c +- (CGSize)sizeThatFits:(CGSize)size +{ + // size the image + CGSize imageSize = [_imageView sizeThatFits:size]; + + // size the text view + CGSize maxTextSize = CGSizeMake(size.width - imageSize.width, size.height); + CGSize textSize = [_textView sizeThatFits:maxTextSize]; + + // make sure everything fits + CGFloat minHeight = MAX(imageSize.height, textSize.height); + return CGSizeMake(size.width, minHeight); +} + +- (void)layoutSubviews +{ + CGSize size = self.bounds.size; // convenience + + // size and layout the image + CGSize imageSize = [_imageView sizeThatFits:size]; + _imageView.frame = CGRectMake(size.width - imageSize.width, 0.0f, + imageSize.width, imageSize.height); + + // size and layout the text view + CGSize maxTextSize = CGSizeMake(size.width - imageSize.width, size.height); + CGSize textSize = [_textView sizeThatFits:maxTextSize]; + _textView.frame = (CGRect){ CGPointZero, textSize }; +} +``` + +This isn't ideal. We're sizing our subviews twice — once to figure out +how big our view needs to be and once when laying it out — and while our +layout arithmetic is cheap and quick, we're also blocking the main thread on +expensive text sizing. + +We could improve the situation by manually cacheing our subviews' sizes, but +that solution comes with its own set of problems. Just adding `_imageSize` and +`_textSize` ivars wouldn't be enough: for example, if the text were to change, +we'd need to recompute its size. The boilerplate would quickly become +untenable. + +Further, even with a cache, we'll still be blocking the main thread on sizing +*sometimes*. We could try to shift sizing to a background thread with +`dispatch_async()`, but even if our own code is thread-safe, UIView methods are +documented to [only work on the main +thread](https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIView_Class/index.html): + +> Manipulations to your application’s user interface must occur on the main +> thread. Thus, you should always call the methods of the UIView class from +> code running in the main thread of your application. The only time this may +> not be strictly necessary is when creating the view object itself but all +> other manipulations should occur on the main thread. + +This is a pretty deep rabbit hole. We could attempt to work around the fact +that UILabels and UITextViews cannot safely be sized on background threads by +manually creating a TextKit stack and sizing the text ourselves... but that's a +laborious duplication of work. Further, if UITextView's layout behaviour +changes in an iOS update, our sizing code will break. (And did we mention that +TextKit isn't thread-safe either?) + +## Node hierarchies + +Enter AsyncDisplayKit. Our custom node looks like this: + +```objective-c +#import + +... + +// perform expensive sizing operations on a background thread +- (CGSize)calculateSizeThatFits:(CGSize)constrainedSize +{ + // size the image + CGSize imageSize = [_imageNode measure:constrainedSize]; + + // size the text node + CGSize maxTextSize = CGSizeMake(constrainedSize.width - imageSize.width, + constrainedSize.height); + CGSize textSize = [_textNode measure:maxTextSize]; + + // make sure everything fits + CGFloat minHeight = MAX(imageSize.height, textSize.height); + return CGSizeMake(constrainedSize.width, minHeight); +} + +// do as little work as possible in main-thread layout +- (void)layout +{ + // layout the image using its cached size + CGSize imageSize = _imageNode.calculatedSize; + _imageNode.frame = CGRectMake(self.bounds.size.width - imageSize.width, 0.0f, + imageSize.width, imageSize.height); + + // layout the text view using its cached size + CGSize textSize = _textNode.calculatedSize; + _textNode.frame = (CGRect){ CGPointZero, textSize }; +} +``` + +ASImageNode and ASTextNode, like the rest of AsyncDisplayKit, are thread-safe, +so we can size them on background threads. The `-measure:` method is like +`-sizeThatFits:`, but with side effects: it caches both the argument +(`constrainedSizeForCalculatedSize`) and the result (`calculatedSize`) for +quick access later on — like in our now-snappy `-layout` implementation. + +As you can see, node hierarchies are sized and laid out in much the same way as +their view counterparts. Custom nodes do need to be written with a few things +in mind: + +* Nodes must recursively measure all of their subnodes in their + `-calculateSizeThatFits:` implementations. Note that the `-measure:` + machinery will only call `-calculateSizeThatFits:` if a new measurement pass + is needed (e.g., if the constrained size has changed). + +* Nodes should perform any other expensive pre-layout calculations in + `-calculateSizeThatFits:`, cacheing useful intermediate results in ivars as + appropriate. + +* Nodes should call `[self invalidateCalculatedSize]` when necessary. For + example, ASTextNode invalidates its calculated size when its + `attributedString` property is changed. + +For more examples of custom sizing and layout, along with a demo of +ASTextNode's features, check out `BlurbNode` and `KittenNode` in the +[Kittens](https://github.com/facebook/AsyncDisplayKit/tree/master/examples/Kittens) +sample project. + +## Custom drawing + +To guarantee thread safety in its highly-concurrent drawing system, the node +drawing API diverges substantially from UIView's. Instead of implementing +`-drawRect:`, you must: + +1. Define an internal "draw parameters" class for your custom node. This + class should be able to store any state your node needs to draw itself + — it can be a plain old NSObject or even a dictionary. + +2. Return a configured instance of your draw parameters class in + `-drawParametersForAsyncLayer:`. This method will always be called on the + main thread. + +3. Implement either `+drawRect:withParameters:isCancelled:isRasterizing:` or + `+displayWithParameters:isCancelled:`. Note that these are *class* methods + that will not have access to your node's state — only the draw + parameters object. They can be called on any thread and must be + thread-safe. + +For example, this node will draw a rainbow: + +```objective-c +@interface RainbowNode : ASDisplayNode +@end + +@implementation RainbowNode + ++ (void)drawRect:(CGRect)bounds + withParameters:(id)parameters + isCancelled:(asdisplaynode_iscancelled_block_t)isCancelledBlock + isRasterizing:(BOOL)isRasterizing +{ + // clear the backing store, but only if we're not rasterising into another layer + if (!isRasterizing) { + [[UIColor whiteColor] set]; + UIRectFill(bounds); + } + + // UIColor sadly lacks +indigoColor and +violetColor methods + NSArray *colors = @[ [UIColor redColor], + [UIColor orangeColor], + [UIColor yellowColor], + [UIColor greenColor], + [UIColor blueColor], + [UIColor purpleColor] ]; + CGFloat stripeHeight = roundf(bounds.size.height / (float)colors.count); + + // draw the stripes + for (UIColor *color in colors) { + CGRect stripe = CGRectZero; + CGRectDivide(bounds, &stripe, &bounds, stripeHeight, CGRectMinYEdge); + [color set]; + UIRectFill(stripe); + } +} + +@end +``` + +This could easily be extended to support vertical rainbows too, by adding a +`vertical` property to the node, exporting it in +`-drawParametersForAsyncLayer:`, and referencing it in +`+drawRect:withParameters:isCancelled:isRasterizing:`. More-complex nodes can +be supported in much the same way. + +For more on custom nodes, check out the [subclassing +header](https://github.com/facebook/AsyncDisplayKit/blob/master/AsyncDisplayKit/ASDisplayNode%2BSubclasses.h) +or read on! diff --git a/docs/guide/3-asynchronous-display.md b/docs/guide/3-asynchronous-display.md new file mode 100644 index 0000000000..acc9f37911 --- /dev/null +++ b/docs/guide/3-asynchronous-display.md @@ -0,0 +1,102 @@ +--- +layout: docs +title: Asynchronous display +permalink: /guide/3/ +prev: guide/2/ +next: guide/4/ +--- + +## Realistic placeholders + +Nodes need to complete both a *measurement pass* and a *display pass* before +they're fully rendered. It's possible to force either step to happen +synchronously: call `-measure:` in `-layoutSubviews` to perform sizing on the +main thread, or set a node's `displaysAsynchronously` flag to NO to disable +ASDK's async display machinery. (AsyncDisplayKit can still improve your app's +performance even when rendering fully synchronously — more on that +later!) + +The recommended way to use ASDK is to only add nodes to your view hierarchy +once they've been sized. This avoids unsightly layout changes as the +measurement pass completes, but if you enable asynchronous display, it will +always be possible for a node to appear onscreen before its content has fully +rendered. We'll discuss techniques to minimise this shortly, but you should +take it into account and include *realistic placeholders* in your app designs. + +Once its measurement pass has completed, a node can accurately place all of its +subnodes onscreen — they'll just be blank. The easiest way to make a +realistic placeholder is to set static background colours on your subnodes. +This effect looks better than generic placeholder images because it varies +based on the content being loaded, and it works particularly well for opaque +images. You can also create visually-appealing placeholder nodes, like the +shimmery lines representing text in Paper as its stories are loaded, and swap +them out with your content nodes once they've finished displaying. + +## Working range + +So far, we've only discussed asynchronous sizing: toss a "create a node +hierarchy and measure it" block onto a background thread, then trampoline to +the main thread to add it to the view hierarchy when that's done. Ideally, as +much content as possible should be fully-rendered and ready to go as soon as +the user scrolls to it. This requires triggering display passes in advance. + +If your app's content is in a scroll view or can be paged through, like +Instagram's main feed or Paper's story strip, the solution is a *working +range*. A working range controller tracks the *visible range*, the subset of +content that's currently visible onscreen, and enqueues asynchronous rendering +for the next few screenfuls of content. As the user scrolls, a screenful or +two of previous content is preserved; the rest is cleared to conserve memory. +If she starts scrolling in the other direction, the working range trashes its +render queue and starts pre-rendering in the new direction of scroll — +and because of the buffer of previous content, this entire process will +typically be invisible. + +AsyncDisplayKit includes a generic working range controller, +`ASRangeController`. Its working range size can be tuned depending on your +app: if your nodes are simple, even an iPhone 4 can maintain a substantial +working range, but heavyweight nodes like Facebook stories are expensive and +need to be pruned quickly. + +```objective-c +ASRangeController *rangeController = [[ASRangeController alloc] init]; +rangeController.tuningParameters = (ASRangeTuningParameters){ + .leadingBufferScreenfuls = 2.0f; // two screenfuls in the direction of scroll + .trailingBufferScreenfuls = 0.5f; // one-half screenful in the other direction +}; +``` + +If you use a working range, you should profile your app and consider tuning it +differently on a per-device basis. iPhone 4 has 512MB of RAM and a single-core +A4 chipset, while iPhone 6 has 1GB of RAM and the orders-of-magnitude-faster +multicore A8 — and if your app supports iOS 7, it will be used on both. + +## ASTableView + +ASRangeController manages working ranges, but doesn't actually display content. +If your content is currently rendered in a UITableView, you can convert it to +use `ASTableView` and custom nodes — just subclass `ASCellNode` instead +of ASDisplayNode. ASTableView is a UITableView subclass that integrates +node-based cells and a working range. + +ASTableView doesn't let cells onscreen until their underlying nodes have been +sized, and as such can fully benefit from realistic placeholders. Its API is +very similar to UITableView (see the +[Kittens](https://github.com/facebook/AsyncDisplayKit/tree/master/examples/Kittens) +sample project for an example), with some key changes: + +* Rather than setting the table view's `.delegate` and `.dataSource`, you set + its `.asyncDelegate` and `.asyncDataSource`. See + [ASTableView.h](https://github.com/facebook/AsyncDisplayKit/blob/master/AsyncDisplayKit/ASTableView.h) + for how its delegate and data source protocols differ from UITableView's. + +* Instead of implementing `-tableView:cellForRowAtIndexPath:`, your data + source must implement `-tableView:nodeForRowAtIndexPath:`. This method must + be thread-safe and should not implement reuse. Unlike the UITableView + version, it won't be called when the row is about to display. + +* `-tableView:heightForRowAtIndexPath:` has been removed — ASTableView + lets your cell nodes size themselves. This means you no longer have to + manually duplicate or factor out layout and sizing logic for + dynamically-sized UITableViewCells! + +Next up, how to get the most out of ASDK in your app. diff --git a/docs/guide/4-making-the-most-of-asdk.md b/docs/guide/4-making-the-most-of-asdk.md new file mode 100644 index 0000000000..f35ad900b4 --- /dev/null +++ b/docs/guide/4-making-the-most-of-asdk.md @@ -0,0 +1,139 @@ +--- +layout: docs +title: Making the most of AsyncDisplayKit +permalink: /guide/4/ +prev: guide/3/ +next: guide/5/ +--- + +## A note on optimisation + +AsyncDisplayKit is powerful and flexible, but it is not a panacea. If your app +has a complex image- or text-heavy user interface, ASDK can definitely help +improve its performance — but if you're blocking the main thread on +network requests, you should consider rearchitecting a few things first. :] + +So why is it worthwhile to change the way we do view layout and rendering, +given that UIKit has always been locked to the main thread and performant iOS +apps have been shipping since iPhone's launch? + +### Modern animations + +Until iOS 7, static animations (à la `+[UIView +animateWithDuration:animations:]`) were the standard. The post-skeuomorphism +redesign brought with it highly-interactive, physics-based animations, with +springs joining the ranks of constant animation functions like +`UIViewAnimationOptionCurveEaseInOut`. + +Classic animations aren't actually executed in your app. They're executed +out-of-process, in the high-priority Core Animation render server. Thanks to +pre-emptive multitasking, an app can block its main thread continuously without +causing the animation to drop a single frame. + +Critically, dynamic animations can't be offloaded the same way, and both +[pop](https://github.com/facebook/pop) and UIKit Dynamics execute physics +simulations on your app's main thread. This is because executing arbitrary +code in the render server would introduce unacceptable latency, even if it +could be done securely. + +Physics-based animations are often interactive, letting you start an animation +and interrupt it before it completes. Paper lets you fling objects across the +screen and catch them before they land, or grab a view that's being pulled by a +spring and tear it off. This requires processing touch events and updating +animation targets in realtime — even short delays for inter-process +communication would shatter the illusion. + +(Fun fact: Inertial scrolling is also a physics animation! UIScrollView has +always implemented its animations on the main thread, which is why stuttery +scrolling is the hallmark of a slow app.) + +### The main-thread bottleneck + +Physics animations aren't the only thing that need to happen on the main +thread. The main thread's [run +loop](https://developer.apple.com/library/ios/documentation/cocoa/conceptual/multithreading/runloopmanagement/runloopmanagement.html) +is responsible for handling touch events and initiating drawing operations +— and with UIKit in the mix, it also has to render text, decode images, +and do any other custom drawing (e.g., using Core Graphics). + +If an iteration of the main thread's run loop takes too long, it will drop an +animation frame and may fail to handle touch events in time. Each iteration of +the run loop must complete within 16ms in order to drive 60fps animations, and +your own code typically has less than 10ms to execute. This means that the +best way to keep your app smooth and responsive is to do as little work on the +main thread as possible. + +What's more, the main thread only executes on one core! Single-threaded view +hierarchies can't take advantage of the multicore CPUs in all modern iOS +devices. This is important for more than just performance reasons — it's +also critical for battery life. Running the CPU on all cores for a short time +is preferable to running one core for an extended amount of time: if the +processor can *race to sleep* by finishing its work and idling faster, it can +spend more time in a low-power mode, improving battery life. + +## When to go asynchronous + +AsyncDisplayKit really shines when used fully asynchronously, shifting both +measurement and rendering passes off the main thread and onto multiple cores. +This requires a completely node-based hierarchy. Just as degrading from +UIViews to CALayers disables view-specific functionality like touch handling +from that point on, degrading from nodes to views disables async behaviour. + +You don't, however, need to convert your app's entire view hierarchy to nodes. +In fact, you shouldn't! Asynchronously bringing up your app's core UI, like +navigation elements or tab bars, would be a very confusing experience. Those +elements of your apps can still be nodes, but should be fully synchronous to +guarantee a fully-usable interface as quickly as possible. (This is why +UIWindow has no node equivalent.) + +There are two key situations where asynchronous hierarchies excel: + +1. *Parallelisation*. Measuring and rendering UITableViewCells (or your app's + equivalent, e.g., story cards in Paper) are embarrassingly parallel + problems. Table cells typically have a fixed width and variable height + determined by their contents — the argument to `-measure:` for one + cell doesn't depend on any other cells' calculations, so we can enqueue an + arbitrary number of cell measurement passes at once. + +2. *Preloading*. An app with five tabs should synchronously load the first + one so content is ready to go as quickly as possible. Once this is + complete and the CPU is idle, why not asynchronously prepare the other tabs + so the user doesn't have to wait? This is inconvenient with views, but + very easy with nodes. + +Paper's asynchronous rendering starts at the story strip. You should profile +your app and watch how people use it in the wild to decide what combination of +synchrony and asynchrony yields the best user experience. + +## Additional optimisations + +Complex hierarchies — even when rendered asynchronously — can +impose a cost because of the sheer number of views involved. Working around +this can be painful, but AsyncDisplayKit makes it easy! + +* *Layer-backing*. In some cases, you can substantially improve your app's + performance by using layers instead of views. Manually converting + view-based code to layers is laborious due to the difference in APIs. + Worse, if at some point you need to enable touch handling or other + view-specific functionality, you have to manually convert everything back + (and risk regressions!). + + With nodes, converting an entire subtree from views to layers is as simple + as... + + rootNode.layerBacked = YES; + + ...and if you need to go back, it's as simple as deleting one line. We + recommend enabling layer-backing as a matter of course in any custom node + that doesn't need touch handling. + +* *Precompositing*. Flattening an entire view hierarchy into a single layer + also improves performance, but comes with a hit to maintainability and + hierarchy-based reasoning. Nodes can do this for you too! + + rootNode.shouldRasterizeDescendants = YES; + + ...will cause the entire node hierarchy from that point on to be rendered + into one layer. + +Next up: AsyncDisplayKit, under the hood. diff --git a/docs/guide/5-under-the-hood.md b/docs/guide/5-under-the-hood.md new file mode 100644 index 0000000000..01229ec3ff --- /dev/null +++ b/docs/guide/5-under-the-hood.md @@ -0,0 +1,89 @@ +--- +layout: docs +title: Under the hood +permalink: /guide/5/ +prev: guide/4/ +--- + +## Node architecture + +*(Skip to the next section if you're not interested in AsyncDisplayKit implementation details.)* + +We've described nodes as an abstraction over views and layers, and shown how to +interact with the underlying UIViews and CALayers when necessary. Nodes don't +wrap or vend their UIKit counterparts, though — an ASImageNode's `.view` +is not a UIImageView! So how do nodes work? + +**NOTE:** Classes whose names begin with `_` are private. Don't use them +directly! + +Creating a node doesn't create its underlying view-layer pair. This is why you +can create nodes cheaply and on background threads. When you use a UIView or +CALayer property on a node, you're actually interacting with a proxy object, +[`_ASPendingState`](https://github.com/facebook/AsyncDisplayKit/blob/master/AsyncDisplayKit/Private/_ASPendingState.h), +that's preconfigured to match UIView and CALayer defaults. + +The first access to a node's `.view` or `.layer` property causes both to be +initialised and configured with the node's current state. If it has subnodes, +they are recursively loaded as well. Once a node has been loaded, the proxy +object is destroyed and the node becomes main-thread-affined — its +properties will update the underlying view directly. (Layer-backed nodes do +the same, not loading views.) + +Nodes are powered by +[`_ASDisplayLayer`](https://github.com/facebook/AsyncDisplayKit/blob/master/AsyncDisplayKit/Details/_ASDisplayLayer.h) +and +[`_ASDisplayView`](https://github.com/facebook/AsyncDisplayKit/blob/master/AsyncDisplayKit/Details/_ASDisplayView.h). +These are lightweight to create and add to their respective hierarchies, and +provide integration points that allow nodes to act as full-fledged views or +layers. It's possible to create nodes that are backed by custom view or layer +classes, but doing so is strongly discouraged as it disables the majority of +ASDK's functionality. + +When Core Animation asks an `_ASDisplayLayer` to draw itself, the request is +forwarded to its node. Unless asynchronous display has been disabled, the +actual draw call won't happen immediately or on the main thread. Instead, a +display block will be added to a background queue. These blocks are executed +in parallel, but you can enable `ASDISPLAYNODE_DELAY_DISPLAY` in +[`ASDisplayNode(AsyncDisplay)`](https://github.com/facebook/AsyncDisplayKit/blob/master/AsyncDisplayKit/Private/ASDisplayNode%2BAsyncDisplay.mm) +to serialise the render system for debugging. + +Common UIView subclass hooks are forwarded from `_ASDisplayView` to its +underlying node, including touch handling, hit-testing, and gesture recogniser +delegate calls. Because an `_ASDisplayView`'s layer is an `_ASDisplayLayer`, +view-backed nodes also participate in asynchronous display. + +## In practice + +What does this mean for your custom nodes? + +You can implement methods like `-touchesBegan:withEvent:` / +`touchesMoved:withEvent:` / `touchesEnded:withEvent:` / +`touchesCancelled:withEvent:` in your nodes exactly as you would in a UIView +subclass. If you find you need a subclass hook that hasn't already been +provided, please file an issue on GitHub — or add it yourself and submit a +pull request! + +If you need to interact or configure your node's underlying view or layer, +don't do so in `-init`. Instead, override `-didLoad` and check if you're +layer-backed: + +```objective-c +- (void)didLoad +{ + [super didLoad]; + + // add a gesture recogniser, if we have a view to add it to + if (!self.layerBacked) { + _gestureRecogniser = [[UITapGestureRecognizer alloc] initWithTarget:self + action:@selector(_tap:)]; + [self.view addGestureRecognizer:_gestureRecogniser]; + } +} +``` + +## *fin.* + +Thanks for reading! If you have any questions, please file a GitHub issue or +post in the [Facebook group](https://www.facebook.com/groups/551597518288687). +We'd love to hear from you. diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 0000000000..ff8065921a --- /dev/null +++ b/docs/index.md @@ -0,0 +1,86 @@ +--- +layout: page +title: Smooth asynchronous user interfaces for iOS apps +--- + +![logo]({{ site.baseurl }}/assets/logo.png) + +AsyncDisplayKit is an iOS framework that keeps even the most complex user +interfaces smooth and responsive. It was originally built to make Facebook's +[Paper](https://facebook.com/paper) possible, and goes hand-in-hand with +[pop](https://github.com/facebook/pop)'s physics-based animations — but +it's just as powerful with UIKit Dynamics and conventional app designs. + + +
+### Quick start + +ASDK is available on [CocoaPods](http://cocoapods.org). Add the following to your Podfile: + +```ruby +pod 'AsyncDisplayKit' +``` + +(ASDK can also be used as a regular static library: Copy the project to your +codebase manually, adding `AsyncDisplayKit.xcodeproj` to your workspace. Add +`libAsyncDisplayKit.a`, AssetsLibrary, and Photos to the "Link Binary With +Libraries" build phase. Include `-lc++ -ObjC` in your project linker flags.) + +Import the framework header, or create an [Objective-C bridging +header](https://developer.apple.com/library/ios/documentation/swift/conceptual/buildingcocoaapps/MixandMatch.html) +if you're using Swift: + +```objective-c +#import +``` + +AsyncDisplayKit Nodes are a thread-safe abstraction layer over UIViews and +CALayers: + +![logo]({{ site.baseurl }}/assets/node-view-layer.png) + +You can construct entire node hierarchies in parallel, or instantiate and size +a single node on a background thread — for example, you could do +something like this in a UIViewController: + +```objective-c +dispatch_async(_backgroundQueue, ^{ + ASTextNode *node = [[ASTextNode alloc] init]; + node.attributedString = [[NSAttributedString alloc] initWithString:@"hello!" + attributes:nil]; + [node measure:CGSizeMake(screenWidth, FLT_MAX)]; + node.frame = (CGRect){ CGPointZero, node.calculatedSize }; + + // self.view isn't a node, so we can only use it on the main thread + dispatch_async(dispatch_get_main_queue(), ^{ + [self.view addSubview:node.view]; + }); +}); +``` + +AsyncDisplayKit at a glance: + +* `ASImageNode` and `ASTextNode` are drop-in replacements for UIImageView and + UITextView. +* `ASMultiplexImageNode` can load and display progressively higher-quality + variants of an image over a slow cell network, letting you quickly show a + low-resolution photo while the full size downloads. +* `ASNetworkImageNode` is a simpler, single-image counterpart to the Multiplex + node. +* `ASTableView` and `ASCollectionView` are a node-aware UITableView and + UICollectionView, respectively, that can asynchronously preload cell nodes + — from loading network data to rendering — all without blocking + the main thread. + +You can also easily [create your own +nodes](https://github.com/facebook/AsyncDisplayKit/blob/master/AsyncDisplayKit/ASDisplayNode%2BSubclasses.h) +to implement node hierarchies or custom drawing. + + +
+### Learn more + +* Read the [Getting Started guide]({{ site.baseurl }}/guide) +* Get the [sample projects](https://github.com/facebook/AsyncDisplayKit/tree/master/examples) +* Browse the [API reference]({{ site.baseurl }}/appledoc) +* Watch the [NSLondon talk](http://vimeo.com/103589245) or the [NSSpain talk](https://www.youtube.com/watch?v=RY_X7l1g79Q) From 56a534349604621383eab9b62b8d84d86bf89514 Mon Sep 17 00:00:00 2001 From: Kiel Gillard Date: Mon, 27 Jun 2016 11:29:28 +1000 Subject: [PATCH 16/43] Collect subnodes passing the test, not the node with the subnodes passing the test. --- AsyncDisplayKit/ASDisplayNodeExtras.mm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AsyncDisplayKit/ASDisplayNodeExtras.mm b/AsyncDisplayKit/ASDisplayNodeExtras.mm index 46eb46daaf..d9601ba9d6 100644 --- a/AsyncDisplayKit/ASDisplayNodeExtras.mm +++ b/AsyncDisplayKit/ASDisplayNodeExtras.mm @@ -144,7 +144,7 @@ static void _ASDisplayNodeFindAllSubnodes(NSMutableArray *array, ASDisplayNode * for (ASDisplayNode *subnode in node.subnodes) { if (block(subnode)) { - [array addObject:node]; + [array addObject:subnode]; } _ASDisplayNodeFindAllSubnodes(array, subnode, block); From cc74fb0cdcdc46daa98ae734d85a92c083b3cf09 Mon Sep 17 00:00:00 2001 From: Kiel Gillard Date: Mon, 27 Jun 2016 12:53:33 +1000 Subject: [PATCH 17/43] Prove the change gets the correct nodes with a pair of tests. --- AsyncDisplayKit.xcodeproj/project.pbxproj | 4 + .../ASDisplayNodeExtrasTests.m | 76 +++++++++++++++++++ 2 files changed, 80 insertions(+) create mode 100644 AsyncDisplayKitTests/ASDisplayNodeExtrasTests.m diff --git a/AsyncDisplayKit.xcodeproj/project.pbxproj b/AsyncDisplayKit.xcodeproj/project.pbxproj index 62c3baffc7..99ed51bbd8 100644 --- a/AsyncDisplayKit.xcodeproj/project.pbxproj +++ b/AsyncDisplayKit.xcodeproj/project.pbxproj @@ -596,6 +596,7 @@ E5711A2C1C840C81009619D4 /* ASIndexedNodeContext.h in Headers */ = {isa = PBXBuildFile; fileRef = E5711A2A1C840C81009619D4 /* ASIndexedNodeContext.h */; }; E5711A2E1C840C96009619D4 /* ASIndexedNodeContext.mm in Sources */ = {isa = PBXBuildFile; fileRef = E5711A2D1C840C96009619D4 /* ASIndexedNodeContext.mm */; }; E5711A301C840C96009619D4 /* ASIndexedNodeContext.mm in Sources */ = {isa = PBXBuildFile; fileRef = E5711A2D1C840C96009619D4 /* ASIndexedNodeContext.mm */; }; + F711994E1D20C21100568860 /* ASDisplayNodeExtrasTests.m in Sources */ = {isa = PBXBuildFile; fileRef = F711994D1D20C21100568860 /* ASDisplayNodeExtrasTests.m */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -965,6 +966,7 @@ E5711A2A1C840C81009619D4 /* ASIndexedNodeContext.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASIndexedNodeContext.h; sourceTree = ""; }; E5711A2D1C840C96009619D4 /* ASIndexedNodeContext.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASIndexedNodeContext.mm; sourceTree = ""; }; EFA731F0396842FF8AB635EE /* libPods-AsyncDisplayKitTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-AsyncDisplayKitTests.a"; sourceTree = BUILT_PRODUCTS_DIR; }; + F711994D1D20C21100568860 /* ASDisplayNodeExtrasTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASDisplayNodeExtrasTests.m; sourceTree = ""; }; FB07EABBCF28656C6297BC2D /* Pods-AsyncDisplayKitTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AsyncDisplayKitTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-AsyncDisplayKitTests/Pods-AsyncDisplayKitTests.debug.xcconfig"; sourceTree = ""; }; /* End PBXFileReference section */ @@ -1210,6 +1212,7 @@ 058D0A36195D057000B7D73C /* ASTextNodeTests.m */, 058D0A37195D057000B7D73C /* ASTextNodeWordKernerTests.mm */, AEEC47E31C21D3D200EC1693 /* ASVideoNodeTests.m */, + F711994D1D20C21100568860 /* ASDisplayNodeExtrasTests.m */, 058D09C6195D04C000B7D73C /* Supporting Files */, 052EE06A1A15A0D8002C6279 /* TestResources */, 2538B6F21BC5D2A2003CA0B4 /* ASCollectionViewFlowLayoutInspectorTests.m */, @@ -2169,6 +2172,7 @@ 9F06E5CD1B4CAF4200F015D8 /* ASCollectionViewTests.m in Sources */, 2911485C1A77147A005D0878 /* ASControlNodeTests.m in Sources */, CC3B208E1C3F7D0A00798563 /* ASWeakSetTests.m in Sources */, + F711994E1D20C21100568860 /* ASDisplayNodeExtrasTests.m in Sources */, ACF6ED5D1B178DC700DA7C62 /* ASDimensionTests.mm in Sources */, 058D0A38195D057000B7D73C /* ASDisplayLayerTests.m in Sources */, 2538B6F31BC5D2A2003CA0B4 /* ASCollectionViewFlowLayoutInspectorTests.m in Sources */, diff --git a/AsyncDisplayKitTests/ASDisplayNodeExtrasTests.m b/AsyncDisplayKitTests/ASDisplayNodeExtrasTests.m new file mode 100644 index 0000000000..6f1731d211 --- /dev/null +++ b/AsyncDisplayKitTests/ASDisplayNodeExtrasTests.m @@ -0,0 +1,76 @@ +// +// ASDisplayNodeExtrasTests.m +// AsyncDisplayKit +// +// Created by Kiel Gillard on 27/06/2016. +// Copyright © 2016 Facebook. All rights reserved. +// + +#import +#import +#import + +@interface ASDisplayNodeExtrasTests : XCTestCase + +@end + +@interface TestDisplayNode : ASDisplayNode +@end + +@implementation TestDisplayNode +@end + +@implementation ASDisplayNodeExtrasTests + +- (void)testShallowFindSubnodesOfSubclass { + ASDisplayNode *supernode = [[ASDisplayNode alloc] initWithLayerBlock:^CALayer * _Nonnull{ + return [CALayer layer]; + }]; + NSUInteger count = 10; + NSMutableArray *expected = [[NSMutableArray alloc] initWithCapacity:count]; + for (NSUInteger nodeIndex = 0; nodeIndex < count; nodeIndex++) { + TestDisplayNode *node = [[TestDisplayNode alloc] initWithLayerBlock:^CALayer * _Nonnull{ + return [CALayer layer]; + }]; + [supernode addSubnode:node]; + [expected addObject:node]; + } + NSArray *found = ASDisplayNodeFindAllSubnodesOfClass(supernode, [TestDisplayNode class]); + XCTAssertEqualObjects(found, expected, @"Expecting %lu %@ nodes, found %lu", (unsigned long)count, [TestDisplayNode class], (unsigned long)found.count); +} + +- (void)testDeepFindSubnodesOfSubclass { + ASDisplayNode *supernode = [[ASDisplayNode alloc] initWithLayerBlock:^CALayer * _Nonnull{ + return [CALayer layer]; + }]; + + const NSUInteger count = 2; + const NSUInteger levels = 2; + const NSUInteger capacity = [[self class] capacityForCount:count levels:levels]; + NSMutableArray *expected = [[NSMutableArray alloc] initWithCapacity:capacity]; + + [[self class] addSubnodesToNode:supernode number:count remainingLevels:levels accumulated:expected]; + + NSArray *found = ASDisplayNodeFindAllSubnodesOfClass(supernode, [TestDisplayNode class]); + XCTAssertEqualObjects(found, expected, @"Expecting %lu %@ nodes, found %lu", (unsigned long)count, [TestDisplayNode class], (unsigned long)found.count); +} + ++ (void)addSubnodesToNode:(ASDisplayNode *)supernode number:(NSUInteger)number remainingLevels:(NSUInteger)level accumulated:(inout NSMutableArray *)expected { + if (level == 0) return; + for (NSUInteger nodeIndex = 0; nodeIndex < number; nodeIndex++) { + TestDisplayNode *node = [[TestDisplayNode alloc] initWithLayerBlock:^CALayer * _Nonnull{ + return [CALayer layer]; + }]; + [supernode addSubnode:node]; + [expected addObject:node]; + [self addSubnodesToNode:node number:number remainingLevels:(level - 1) accumulated:expected]; + } +} + +// Graph theory is failing me atm. ++ (NSUInteger)capacityForCount:(NSUInteger)count levels:(NSUInteger)level { + if (level == 0) return 0; + return pow(count, level) + [self capacityForCount:count levels:(level - 1)]; +} + +@end From db04f4b851a069794a77ab45115db669b87b1683 Mon Sep 17 00:00:00 2001 From: Hannah Troisi Date: Sun, 26 Jun 2016 23:09:53 -0700 Subject: [PATCH 18/43] [ASTableView] Add constrainedSizeForRowAtIndexPath: to control row heights from delegate (#1769) * [ASTableView] constrainedSizeForRowAtIndexPath * Quick fix to header file * Switch to Delegate from DataSource. * Update testing variables to reflect switch to delegate --- AsyncDisplayKit/ASTableView.h | 12 ++++++++ AsyncDisplayKit/ASTableView.mm | 17 ++++++++-- AsyncDisplayKitTests/ASTableViewTests.m | 41 ++++++++++++++++++++++++- 3 files changed, 67 insertions(+), 3 deletions(-) diff --git a/AsyncDisplayKit/ASTableView.h b/AsyncDisplayKit/ASTableView.h index 7d36cc3d4d..06ce862606 100644 --- a/AsyncDisplayKit/ASTableView.h +++ b/AsyncDisplayKit/ASTableView.h @@ -433,6 +433,18 @@ NS_ASSUME_NONNULL_BEGIN */ - (BOOL)shouldBatchFetchForTableView:(ASTableView *)tableView; +/** + * Provides the constrained size range for measuring the row at the index path. + * Note: the widths in the returned size range are ignored! + * + * @param tableView The sender. + * + * @param indexPath The index path of the node. + * + * @returns A constrained size range for layout the node at this index path. + */ +- (ASSizeRange)tableView:(ASTableView *)tableView constrainedSizeForRowAtIndexPath:(NSIndexPath *)indexPath; + /** * Informs the delegate that the table view did remove the node which was previously * at the given index path from the view hierarchy. diff --git a/AsyncDisplayKit/ASTableView.mm b/AsyncDisplayKit/ASTableView.mm index c978bb9e5e..f3f3177a9e 100644 --- a/AsyncDisplayKit/ASTableView.mm +++ b/AsyncDisplayKit/ASTableView.mm @@ -28,6 +28,7 @@ #import +static const ASSizeRange kInvalidSizeRange = {CGSizeZero, CGSizeZero}; static NSString * const kCellReuseIdentifier = @"_ASTableViewCell"; //#define LOG(...) NSLog(__VA_ARGS__) @@ -125,6 +126,7 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell"; unsigned int asyncDelegateScrollViewWillEndDraggingWithVelocityTargetContentOffset:1; unsigned int asyncDelegateTableViewWillBeginBatchFetchWithContext:1; unsigned int asyncDelegateShouldBatchFetchForTableView:1; + unsigned int asyncDelegateTableViewConstrainedSizeForRowAtIndexPath:1; } _asyncDelegateFlags; struct { @@ -316,6 +318,8 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell"; _asyncDelegateFlags.asyncDelegateShouldBatchFetchForTableView = [_asyncDelegate respondsToSelector:@selector(shouldBatchFetchForTableView:)]; _asyncDelegateFlags.asyncDelegateScrollViewWillBeginDragging = [_asyncDelegate respondsToSelector:@selector(scrollViewWillBeginDragging:)]; _asyncDelegateFlags.asyncDelegateScrollViewDidEndDragging = [_asyncDelegate respondsToSelector:@selector(scrollViewDidEndDragging:willDecelerate:)]; + _asyncDelegateFlags.asyncDelegateTableViewConstrainedSizeForRowAtIndexPath = [_asyncDelegate respondsToSelector:@selector(tableView:constrainedSizeForRowAtIndexPath:)]; + } super.delegate = (id)_proxyDelegate; @@ -1069,8 +1073,17 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell"; - (ASSizeRange)dataController:(ASDataController *)dataController constrainedSizeForNodeAtIndexPath:(NSIndexPath *)indexPath { - return ASSizeRangeMake(CGSizeMake(_nodesConstrainedWidth, 0), - CGSizeMake(_nodesConstrainedWidth, FLT_MAX)); + ASSizeRange constrainedSize = kInvalidSizeRange; + if (_asyncDelegateFlags.asyncDelegateTableViewConstrainedSizeForRowAtIndexPath) { + ASSizeRange delegateConstrainedSize = [_asyncDelegate tableView:self constrainedSizeForRowAtIndexPath:indexPath]; + // ignore widths in the returned size range (for TableView) + constrainedSize = ASSizeRangeMake(CGSizeMake(_nodesConstrainedWidth, delegateConstrainedSize.min.height), + CGSizeMake(_nodesConstrainedWidth, delegateConstrainedSize.max.height)); + } else { + constrainedSize = ASSizeRangeMake(CGSizeMake(_nodesConstrainedWidth, 0), + CGSizeMake(_nodesConstrainedWidth, FLT_MAX)); + } + return constrainedSize; } - (NSUInteger)dataController:(ASDataController *)dataController rowsInSection:(NSUInteger)section diff --git a/AsyncDisplayKitTests/ASTableViewTests.m b/AsyncDisplayKitTests/ASTableViewTests.m index 7cb13fb8ca..98914d1bd4 100644 --- a/AsyncDisplayKitTests/ASTableViewTests.m +++ b/AsyncDisplayKitTests/ASTableViewTests.m @@ -128,7 +128,6 @@ return textCellNode; } - - (ASCellNodeBlock)tableView:(ASTableView *)tableView nodeBlockForRowAtIndexPath:(NSIndexPath *)indexPath { return ^{ @@ -140,12 +139,52 @@ @end +@interface ASTableViewFilledDelegate : NSObject +@end + +@implementation ASTableViewFilledDelegate + +- (ASSizeRange)tableView:(ASTableView *)tableView constrainedSizeForRowAtIndexPath:(NSIndexPath *)indexPath +{ + return ASSizeRangeMakeExactSize(CGSizeMake(10, 42)); +} + +@end + @interface ASTableViewTests : XCTestCase @property (atomic, retain) ASTableView *testTableView; @end @implementation ASTableViewTests +- (void)testConstrainedSizeForRowAtIndexPath +{ + // Initial width of the table view is non-zero and all nodes are measured with this size. + // Any subsequence size change must trigger a relayout. + // Width and height are swapped so that a later size change will simulate a rotation + ASTestTableView *tableView = [[ASTestTableView alloc] __initWithFrame:CGRectMake(0, 0, 100, 400) + style:UITableViewStylePlain]; + + ASTableViewFilledDelegate *delegate = [ASTableViewFilledDelegate new]; + ASTableViewFilledDataSource *dataSource = [ASTableViewFilledDataSource new]; + + tableView.asyncDelegate = delegate; + tableView.asyncDataSource = dataSource; + + [tableView reloadDataImmediately]; + [tableView setNeedsLayout]; + [tableView layoutIfNeeded]; + + for (int section = 0; section < NumberOfSections; section++) { + for (int row = 0; row < NumberOfRowsPerSection; row++) { + NSIndexPath *indexPath = [NSIndexPath indexPathForRow:row inSection:section]; + CGRect rect = [tableView rectForRowAtIndexPath:indexPath]; + XCTAssertEqual(rect.size.width, 100); // specified width should be ignored for table + XCTAssertEqual(rect.size.height, 42); + } + } +} + // TODO: Convert this to ARC. - (void)DISABLED_testTableViewDoesNotRetainItselfAndDelegate { From d55621c285480131045de2a87fc3fe39fd3d4412 Mon Sep 17 00:00:00 2001 From: Gareth Reese Date: Mon, 27 Jun 2016 14:07:00 +0100 Subject: [PATCH 19/43] [ASCollectionView] Tuning parameters not set --- AsyncDisplayKit/ASCollectionView.mm | 8 ++-- AsyncDisplayKitTests/ASCollectionViewTests.m | 41 ++++++++++++++++++++ 2 files changed, 45 insertions(+), 4 deletions(-) diff --git a/AsyncDisplayKit/ASCollectionView.mm b/AsyncDisplayKit/ASCollectionView.mm index 68031f464a..521cfde856 100644 --- a/AsyncDisplayKit/ASCollectionView.mm +++ b/AsyncDisplayKit/ASCollectionView.mm @@ -411,22 +411,22 @@ static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell"; - (void)setTuningParameters:(ASRangeTuningParameters)tuningParameters forRangeType:(ASLayoutRangeType)rangeType { - [_collectionNode setTuningParameters:tuningParameters forRangeType:rangeType]; + [_rangeController setTuningParameters:tuningParameters forRangeMode:ASLayoutRangeModeFull rangeType:rangeType]; } - (ASRangeTuningParameters)tuningParametersForRangeType:(ASLayoutRangeType)rangeType { - return [_collectionNode tuningParametersForRangeType:rangeType]; + return [_rangeController tuningParametersForRangeMode:ASLayoutRangeModeFull rangeType:rangeType]; } - (void)setTuningParameters:(ASRangeTuningParameters)tuningParameters forRangeMode:(ASLayoutRangeMode)rangeMode rangeType:(ASLayoutRangeType)rangeType { - [_collectionNode setTuningParameters:tuningParameters forRangeMode:rangeMode rangeType:rangeType]; + [_rangeController setTuningParameters:tuningParameters forRangeMode:rangeMode rangeType:rangeType]; } - (ASRangeTuningParameters)tuningParametersForRangeMode:(ASLayoutRangeMode)rangeMode rangeType:(ASLayoutRangeType)rangeType { - return [_collectionNode tuningParametersForRangeMode:rangeMode rangeType:rangeType]; + return [_rangeController tuningParametersForRangeMode:rangeMode rangeType:rangeType]; } - (CGSize)calculatedSizeForNodeAtIndexPath:(NSIndexPath *)indexPath diff --git a/AsyncDisplayKitTests/ASCollectionViewTests.m b/AsyncDisplayKitTests/ASCollectionViewTests.m index 4c7f84aec3..2ed3584149 100644 --- a/AsyncDisplayKitTests/ASCollectionViewTests.m +++ b/AsyncDisplayKitTests/ASCollectionViewTests.m @@ -134,4 +134,45 @@ [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:1.0]]; } +- (void)testTuningParametersWithExplicitRangeMode +{ + UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init]; + ASCollectionView *collectionView = [[ASCollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:layout]; + + ASRangeTuningParameters minimumRenderParams = { .leadingBufferScreenfuls = 0.1, .trailingBufferScreenfuls = 0.1 }; + ASRangeTuningParameters minimumPreloadParams = { .leadingBufferScreenfuls = 0.1, .trailingBufferScreenfuls = 0.1 }; + ASRangeTuningParameters fullRenderParams = { .leadingBufferScreenfuls = 0.5, .trailingBufferScreenfuls = 0.5 }; + ASRangeTuningParameters fullPreloadParams = { .leadingBufferScreenfuls = 1, .trailingBufferScreenfuls = 0.5 }; + + [collectionView setTuningParameters:minimumRenderParams forRangeMode:ASLayoutRangeModeMinimum rangeType:ASLayoutRangeTypeDisplay]; + [collectionView setTuningParameters:minimumPreloadParams forRangeMode:ASLayoutRangeModeMinimum rangeType:ASLayoutRangeTypeFetchData]; + [collectionView setTuningParameters:fullRenderParams forRangeMode:ASLayoutRangeModeFull rangeType:ASLayoutRangeTypeDisplay]; + [collectionView setTuningParameters:fullPreloadParams forRangeMode:ASLayoutRangeModeFull rangeType:ASLayoutRangeTypeFetchData]; + + XCTAssertTrue(ASRangeTuningParametersEqualToRangeTuningParameters(minimumRenderParams, + [collectionView tuningParametersForRangeMode:ASLayoutRangeModeMinimum rangeType:ASLayoutRangeTypeDisplay])); + XCTAssertTrue(ASRangeTuningParametersEqualToRangeTuningParameters(minimumPreloadParams, + [collectionView tuningParametersForRangeMode:ASLayoutRangeModeMinimum rangeType:ASLayoutRangeTypeFetchData])); + XCTAssertTrue(ASRangeTuningParametersEqualToRangeTuningParameters(fullRenderParams, + [collectionView tuningParametersForRangeMode:ASLayoutRangeModeFull rangeType:ASLayoutRangeTypeDisplay])); + XCTAssertTrue(ASRangeTuningParametersEqualToRangeTuningParameters(fullPreloadParams, + [collectionView tuningParametersForRangeMode:ASLayoutRangeModeFull rangeType:ASLayoutRangeTypeFetchData])); +} + +- (void)testTuningParameters +{ + UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init]; + ASCollectionView *collectionView = [[ASCollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:layout]; + + ASRangeTuningParameters renderParams = { .leadingBufferScreenfuls = 1.2, .trailingBufferScreenfuls = 3.2 }; + ASRangeTuningParameters preloadParams = { .leadingBufferScreenfuls = 4.3, .trailingBufferScreenfuls = 2.3 }; + + [collectionView setTuningParameters:renderParams forRangeType:ASLayoutRangeTypeDisplay]; + [collectionView setTuningParameters:preloadParams forRangeType:ASLayoutRangeTypeFetchData]; + + XCTAssertTrue(ASRangeTuningParametersEqualToRangeTuningParameters(renderParams, [collectionView tuningParametersForRangeType:ASLayoutRangeTypeDisplay])); + XCTAssertTrue(ASRangeTuningParametersEqualToRangeTuningParameters(preloadParams, [collectionView tuningParametersForRangeType:ASLayoutRangeTypeFetchData])); +} + + @end From 4091d700032d13eb674d5d946af780b411718b40 Mon Sep 17 00:00:00 2001 From: Michael Schneider Date: Mon, 27 Jun 2016 06:38:42 -0700 Subject: [PATCH 20/43] Add `conformsToProtocol:` to ASDelegateProxy --- AsyncDisplayKit/Details/ASDelegateProxy.m | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/AsyncDisplayKit/Details/ASDelegateProxy.m b/AsyncDisplayKit/Details/ASDelegateProxy.m index b1f3310736..13c0d211c9 100644 --- a/AsyncDisplayKit/Details/ASDelegateProxy.m +++ b/AsyncDisplayKit/Details/ASDelegateProxy.m @@ -118,6 +118,15 @@ return self; } +- (BOOL)conformsToProtocol:(Protocol *)aProtocol +{ + if (_target) { + return [_target conformsToProtocol:aProtocol]; + } else { + return [super conformsToProtocol:aProtocol]; + } +} + - (BOOL)respondsToSelector:(SEL)aSelector { if ([self interceptsSelector:aSelector]) { From f7fa90aafdf7a14425c75b971671925caa89331c Mon Sep 17 00:00:00 2001 From: Adlai Holler Date: Mon, 27 Jun 2016 10:21:52 -0700 Subject: [PATCH 21/43] [Project] Publicize ASPINRemoteImageDownloader.h --- AsyncDisplayKit.xcodeproj/project.pbxproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/AsyncDisplayKit.xcodeproj/project.pbxproj b/AsyncDisplayKit.xcodeproj/project.pbxproj index 62c3baffc7..9a58257452 100644 --- a/AsyncDisplayKit.xcodeproj/project.pbxproj +++ b/AsyncDisplayKit.xcodeproj/project.pbxproj @@ -256,9 +256,9 @@ 68355B3A1CB57A5A001D4E68 /* ASPINRemoteImageDownloader.m in Sources */ = {isa = PBXBuildFile; fileRef = 68355B361CB57A5A001D4E68 /* ASPINRemoteImageDownloader.m */; }; 68355B3B1CB57A5A001D4E68 /* ASImageContainerProtocolCategories.h in Headers */ = {isa = PBXBuildFile; fileRef = 68355B371CB57A5A001D4E68 /* ASImageContainerProtocolCategories.h */; settings = {ATTRIBUTES = (Public, ); }; }; 68355B3C1CB57A5A001D4E68 /* ASImageContainerProtocolCategories.m in Sources */ = {isa = PBXBuildFile; fileRef = 68355B381CB57A5A001D4E68 /* ASImageContainerProtocolCategories.m */; }; - 68355B3D1CB57A5A001D4E68 /* ASPINRemoteImageDownloader.h in Headers */ = {isa = PBXBuildFile; fileRef = 68355B391CB57A5A001D4E68 /* ASPINRemoteImageDownloader.h */; }; + 68355B3D1CB57A5A001D4E68 /* ASPINRemoteImageDownloader.h in Headers */ = {isa = PBXBuildFile; fileRef = 68355B391CB57A5A001D4E68 /* ASPINRemoteImageDownloader.h */; settings = {ATTRIBUTES = (Public, ); }; }; 68355B3E1CB57A60001D4E68 /* ASPINRemoteImageDownloader.m in Sources */ = {isa = PBXBuildFile; fileRef = 68355B361CB57A5A001D4E68 /* ASPINRemoteImageDownloader.m */; }; - 68355B3F1CB57A64001D4E68 /* ASPINRemoteImageDownloader.h in Headers */ = {isa = PBXBuildFile; fileRef = 68355B391CB57A5A001D4E68 /* ASPINRemoteImageDownloader.h */; }; + 68355B3F1CB57A64001D4E68 /* ASPINRemoteImageDownloader.h in Headers */ = {isa = PBXBuildFile; fileRef = 68355B391CB57A5A001D4E68 /* ASPINRemoteImageDownloader.h */; settings = {ATTRIBUTES = (Public, ); }; }; 68355B401CB57A69001D4E68 /* ASImageContainerProtocolCategories.m in Sources */ = {isa = PBXBuildFile; fileRef = 68355B381CB57A5A001D4E68 /* ASImageContainerProtocolCategories.m */; }; 68355B411CB57A6C001D4E68 /* ASImageContainerProtocolCategories.h in Headers */ = {isa = PBXBuildFile; fileRef = 68355B371CB57A5A001D4E68 /* ASImageContainerProtocolCategories.h */; settings = {ATTRIBUTES = (Public, ); }; }; 68AF37DB1CBEF4D80077BF76 /* ASImageNode+AnimatedImagePrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 68B8A4DB1CBD911D007E4543 /* ASImageNode+AnimatedImagePrivate.h */; }; From 20edc81f55f70357f8be7896ce72ce6442451e66 Mon Sep 17 00:00:00 2001 From: Hannah Troisi Date: Mon, 27 Jun 2016 11:19:32 -0700 Subject: [PATCH 22/43] Update build.sh file Adding MODE = "examples" will allow Kosta to speed up internal ASDK build. --- build.sh | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/build.sh b/build.sh index 02a2ddb4ab..e6f1f0566f 100755 --- a/build.sh +++ b/build.sh @@ -36,6 +36,46 @@ if [ "$MODE" = "tests" ]; then exit 0 fi +if [ "$MODE" = "examples" ]; then + echo "Verifying that all AsyncDisplayKit examples compile." + + for example in examples/*/; do + echo "Building (examples) $example." + + if [ -f "${example}/Podfile" ]; then + echo "Using CocoaPods" + pod install --project-directory=$example + + set -o pipefail && xcodebuild \ + -workspace "${example}/Sample.xcworkspace" \ + -scheme Sample \ + -sdk "$SDK" \ + -destination "$PLATFORM" \ + -derivedDataPath ~/ \ + build | xcpretty $FORMATTER + elif [ -f "${example}/Cartfile" ]; then + echo "Using Carthage" + local_repo=`pwd` + current_branch=`git rev-parse --abbrev-ref HEAD` + cd $example + + echo "git \"file://${local_repo}\" \"${current_branch}\"" > "Cartfile" + carthage update --platform iOS + + set -o pipefail && xcodebuild \ + -project "Sample.xcodeproj" \ + -scheme Sample \ + -sdk "$SDK" \ + -destination "$PLATFORM" \ + build | xcpretty $FORMATTER + + cd ../.. + fi + done + trap - EXIT + exit 0 +fi + if [ "$MODE" = "examples-pt1" ]; then echo "Verifying that all AsyncDisplayKit examples compile." From e0fc55e25f566e1e594dd8b5f8548a0b651e7d83 Mon Sep 17 00:00:00 2001 From: Hannah Troisi Date: Mon, 27 Jun 2016 16:57:08 -0700 Subject: [PATCH 23/43] Jenkins build test Adding a space to test jenkins build hooks. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 10f28e5005..69808652ab 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ ASDK is available on [CocoaPods](http://cocoapods.org). Add the following to yo ```ruby pod 'AsyncDisplayKit' ``` - + (ASDK can also be used as a regular static library: Copy the project to your codebase manually, adding `AsyncDisplayKit.xcodeproj` to your workspace. Add `libAsyncDisplayKit.a`, MapKit, AssetsLibrary, and Photos to the "Link Binary With From c10497ed99d7e813249389d388e053fc1d4ab5b1 Mon Sep 17 00:00:00 2001 From: Hannah Troisi Date: Mon, 27 Jun 2016 17:07:53 -0700 Subject: [PATCH 24/43] Jenkins build test 2 Added a space to trigger a Jenkins build. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 69808652ab..f0ffdee12f 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ [![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-59C939.svg?style=flat)](https://github.com/Carthage/Carthage) [![Build Status](https://travis-ci.org/facebook/AsyncDisplayKit.svg)](https://travis-ci.org/facebook/AsyncDisplayKit) [![License](https://img.shields.io/cocoapods/l/AsyncDisplayKit.svg)](https://github.com/facebook/AsyncDisplayKit/blob/master/LICENSE) - + AsyncDisplayKit is an iOS framework that keeps even the most complex user interfaces smooth and responsive. It was originally built to make Facebook's From ceff3e89878f7dd7e0cc9660b128f995b63d88fe Mon Sep 17 00:00:00 2001 From: Hannah Troisi Date: Mon, 27 Jun 2016 17:14:24 -0700 Subject: [PATCH 25/43] Jenkins build test 3 added another space --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f0ffdee12f..13335eb7ac 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ interfaces smooth and responsive. It was originally built to make Facebook's [pop](https://github.com/facebook/pop)'s physics-based animations — but it's just as powerful with UIKit Dynamics and conventional app designs. -### Quick start +### Quick start ASDK is available on [CocoaPods](http://cocoapods.org). Add the following to your Podfile: From 0414cf7c9b86ddef6a345bb5cb4f67869e89ace7 Mon Sep 17 00:00:00 2001 From: Hannah Troisi Date: Mon, 27 Jun 2016 17:24:01 -0700 Subject: [PATCH 26/43] Jenkins build test 4 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 13335eb7ac..c7f6218626 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ interfaces smooth and responsive. It was originally built to make Facebook's [pop](https://github.com/facebook/pop)'s physics-based animations — but it's just as powerful with UIKit Dynamics and conventional app designs. -### Quick start +### Quick start ASDK is available on [CocoaPods](http://cocoapods.org). Add the following to your Podfile: From db9826c4c62a718f93efe8169e8b0684bba949ca Mon Sep 17 00:00:00 2001 From: Adlai Holler Date: Mon, 27 Jun 2016 17:30:06 -0700 Subject: [PATCH 27/43] Add a space for Jenkins testing --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c7f6218626..812826197f 100644 --- a/README.md +++ b/README.md @@ -46,7 +46,7 @@ CALayers: You can construct entire node hierarchies in parallel, or instantiate and size a single node on a background thread — for example, you could do -something like this in a UIViewController: +something like this in a UIViewController: ```objective-c dispatch_async(_backgroundQueue, ^{ From 1d356242fd04bf77c00e29dd7b9d1ddb891facec Mon Sep 17 00:00:00 2001 From: Gareth Reese Date: Tue, 28 Jun 2016 15:41:26 +0100 Subject: [PATCH 28/43] [ASVideoNode] Ensure that observer methods don't observer all other ASVideoNode objects --- AsyncDisplayKit/ASVideoNode.mm | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/AsyncDisplayKit/ASVideoNode.mm b/AsyncDisplayKit/ASVideoNode.mm index 379a70955b..13d469ea89 100644 --- a/AsyncDisplayKit/ASVideoNode.mm +++ b/AsyncDisplayKit/ASVideoNode.mm @@ -164,6 +164,10 @@ static NSString * const kStatus = @"status"; - (void)addPlayerItemObservers:(AVPlayerItem *)playerItem { + if (playerItem == nil) { + return; + } + [playerItem addObserver:self forKeyPath:kStatus options:NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew context:ASVideoNodeContext]; [playerItem addObserver:self forKeyPath:kPlaybackLikelyToKeepUpKey options:NSKeyValueObservingOptionNew context:ASVideoNodeContext]; [playerItem addObserver:self forKeyPath:kplaybackBufferEmpty options:NSKeyValueObservingOptionNew context:ASVideoNodeContext]; @@ -641,7 +645,9 @@ static NSString * const kStatus = @"status"; _currentPlayerItem = currentItem; - [self addPlayerItemObservers:currentItem]; + if (currentItem != nil) { + [self addPlayerItemObservers:currentItem]; + } } - (ASDisplayNode *)playerNode From 45ef91171d5c1505bd2c5a9d00f13732402a09ba Mon Sep 17 00:00:00 2001 From: Adlai Holler Date: Tue, 28 Jun 2016 20:18:30 -0700 Subject: [PATCH 29/43] [ASTextNode] Release Lock Sooner in -setAttributedText: (#1828) * [ASTextNode] Release lock sooner in -setAttributedText: * [ASTextNode] Expand the critical scope a bit --- AsyncDisplayKit/ASTextNode.mm | 48 +++++++++++++++++++---------------- 1 file changed, 26 insertions(+), 22 deletions(-) diff --git a/AsyncDisplayKit/ASTextNode.mm b/AsyncDisplayKit/ASTextNode.mm index a1e3d6c3e7..3151437f55 100644 --- a/AsyncDisplayKit/ASTextNode.mm +++ b/AsyncDisplayKit/ASTextNode.mm @@ -366,31 +366,35 @@ static NSArray *DefaultLinkAttributeNames = @[ NSLinkAttributeName ]; - (void)setAttributedText:(NSAttributedString *)attributedText { - std::lock_guard l(_textLock); if (attributedText == nil) { attributedText = [[NSAttributedString alloc] initWithString:@"" attributes:nil]; } - - if (ASObjectIsEqual(attributedText, _attributedText)) { - return; - } - - _attributedText = ASCleanseAttributedStringOfCoreTextAttributes(attributedText); - - if (_attributedText.length > 0) { - CGFloat screenScale = ASScreenScale(); - self.ascender = round([[_attributedText attribute:NSFontAttributeName atIndex:0 effectiveRange:NULL] ascender] * screenScale)/screenScale; - self.descender = round([[_attributedText attribute:NSFontAttributeName atIndex:_attributedText.length - 1 effectiveRange:NULL] descender] * screenScale)/screenScale; - } - - // Sync the truncation string with attributes from the updated _attributedString - // Without this, the size calculation of the text with truncation applied will - // not take into account the attributes of attributedText in the last line - [self _updateComposedTruncationText]; - // We need an entirely new renderer - [self _invalidateRenderer]; + // Don't hold textLock for too long. + { + std::lock_guard l(_textLock); + if (ASObjectIsEqual(attributedText, _attributedText)) { + return; + } + + _attributedText = ASCleanseAttributedStringOfCoreTextAttributes(attributedText); + + // Sync the truncation string with attributes from the updated _attributedString + // Without this, the size calculation of the text with truncation applied will + // not take into account the attributes of attributedText in the last line + [self _updateComposedTruncationText]; + + // We need an entirely new renderer + [self _invalidateRenderer]; + } + + NSUInteger length = attributedText.length; + if (length > 0) { + CGFloat screenScale = ASScreenScale(); + self.ascender = round([[attributedText attribute:NSFontAttributeName atIndex:0 effectiveRange:NULL] ascender] * screenScale)/screenScale; + self.descender = round([[attributedText attribute:NSFontAttributeName atIndex:length - 1 effectiveRange:NULL] descender] * screenScale)/screenScale; + } // Tell the display node superclasses that the cached layout is incorrect now [self invalidateCalculatedLayout]; @@ -399,8 +403,8 @@ static NSArray *DefaultLinkAttributeNames = @[ NSLinkAttributeName ]; // Accessiblity - self.accessibilityLabel = _attributedText.string; - self.isAccessibilityElement = (_attributedText.length != 0); // We're an accessibility element by default if there is a string. + self.accessibilityLabel = attributedText.string; + self.isAccessibilityElement = (length != 0); // We're an accessibility element by default if there is a string. } #pragma mark - Text Layout From f0e96cc80880fab16bce6c6f4cd8a4405c2d2579 Mon Sep 17 00:00:00 2001 From: Michael Schneider Date: Thu, 30 Jun 2016 07:18:30 -0700 Subject: [PATCH 30/43] Change @import to #import --- AsyncDisplayKit/Details/NSIndexSet+ASHelpers.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AsyncDisplayKit/Details/NSIndexSet+ASHelpers.m b/AsyncDisplayKit/Details/NSIndexSet+ASHelpers.m index 0837ad0eaa..fa636ad8c8 100644 --- a/AsyncDisplayKit/Details/NSIndexSet+ASHelpers.m +++ b/AsyncDisplayKit/Details/NSIndexSet+ASHelpers.m @@ -6,7 +6,7 @@ // Copyright © 2016 Facebook. All rights reserved. // -@import UIKit; +#import #import "NSIndexSet+ASHelpers.h" From 5f7cdbd9ca6cfe8af9302a7abfb88de69c487634 Mon Sep 17 00:00:00 2001 From: Michael Schneider Date: Mon, 20 Jun 2016 17:07:26 -0700 Subject: [PATCH 31/43] Handle placeholder layer creation in case the size of the node changed after the initial placeholder layer was created --- AsyncDisplayKit/ASDisplayNode.mm | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/AsyncDisplayKit/ASDisplayNode.mm b/AsyncDisplayKit/ASDisplayNode.mm index e38731e7f8..1329254041 100644 --- a/AsyncDisplayKit/ASDisplayNode.mm +++ b/AsyncDisplayKit/ASDisplayNode.mm @@ -1100,7 +1100,14 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c) // measureWithSizeRange: on subnodes to assert. return; } + + // Handle placeholder layer creation in case the size of the node changed after the initial placeholder layer + // was created + if ([self _shouldHavePlaceholderLayer]) { + [self _setupPlaceholderLayerIfNeeded]; + } _placeholderLayer.frame = bounds; + [self layout]; [self layoutDidFinish]; } From d1b4e07d0ff2236b1c51fc546075d890eb16c144 Mon Sep 17 00:00:00 2001 From: Michael Schneider Date: Thu, 23 Jun 2016 14:07:34 -0700 Subject: [PATCH 32/43] Add support for 'preferredFrameSize' to ASButtonNode --- AsyncDisplayKit/ASButtonNode.mm | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/AsyncDisplayKit/ASButtonNode.mm b/AsyncDisplayKit/ASButtonNode.mm index 5638e7c125..864827ae76 100644 --- a/AsyncDisplayKit/ASButtonNode.mm +++ b/AsyncDisplayKit/ASButtonNode.mm @@ -15,6 +15,7 @@ #import "ASBackgroundLayoutSpec.h" #import "ASInsetLayoutSpec.h" #import "ASDisplayNode+Beta.h" +#import "ASStaticLayoutSpec.h" @interface ASButtonNode () { @@ -491,6 +492,12 @@ spec = [ASInsetLayoutSpec insetLayoutSpecWithInsets:contentEdgeInsets child:spec]; } + if (CGSizeEqualToSize(self.preferredFrameSize, CGSizeZero) == NO) { + // Handle preferred frame size + stack.sizeRange = ASRelativeSizeRangeMakeWithExactCGSize(self.preferredFrameSize); + spec = [ASStaticLayoutSpec staticLayoutSpecWithChildren:@[stack]]; + } + if (_backgroundImageNode.image) { spec = [ASBackgroundLayoutSpec backgroundLayoutSpecWithChild:spec background:_backgroundImageNode]; From 53f22da1dc7aaf5462d8e8c616338309ad79d916 Mon Sep 17 00:00:00 2001 From: Michael Schneider Date: Thu, 23 Jun 2016 14:11:11 -0700 Subject: [PATCH 33/43] Code style improvements --- AsyncDisplayKit/ASButtonNode.mm | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/AsyncDisplayKit/ASButtonNode.mm b/AsyncDisplayKit/ASButtonNode.mm index 864827ae76..54c30ad47e 100644 --- a/AsyncDisplayKit/ASButtonNode.mm +++ b/AsyncDisplayKit/ASButtonNode.mm @@ -493,14 +493,12 @@ } if (CGSizeEqualToSize(self.preferredFrameSize, CGSizeZero) == NO) { - // Handle preferred frame size stack.sizeRange = ASRelativeSizeRangeMakeWithExactCGSize(self.preferredFrameSize); spec = [ASStaticLayoutSpec staticLayoutSpecWithChildren:@[stack]]; } if (_backgroundImageNode.image) { - spec = [ASBackgroundLayoutSpec backgroundLayoutSpecWithChild:spec - background:_backgroundImageNode]; + spec = [ASBackgroundLayoutSpec backgroundLayoutSpecWithChild:spec background:_backgroundImageNode]; } return spec; From 27b99cf0b6147aa03dceb4914e255c9d70a83d3e Mon Sep 17 00:00:00 2001 From: Adlai Holler Date: Thu, 30 Jun 2016 08:46:11 -0700 Subject: [PATCH 34/43] Make NSIndexSet helpers framework-visible --- AsyncDisplayKit.xcodeproj/project.pbxproj | 2 ++ 1 file changed, 2 insertions(+) diff --git a/AsyncDisplayKit.xcodeproj/project.pbxproj b/AsyncDisplayKit.xcodeproj/project.pbxproj index 9fa6625a99..3e23e8b999 100644 --- a/AsyncDisplayKit.xcodeproj/project.pbxproj +++ b/AsyncDisplayKit.xcodeproj/project.pbxproj @@ -552,6 +552,7 @@ CC7FD9DF1BB5E962005CCB2B /* ASPhotosFrameworkImageRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = CC7FD9DD1BB5E962005CCB2B /* ASPhotosFrameworkImageRequest.m */; }; CC7FD9E11BB5F750005CCB2B /* ASPhotosFrameworkImageRequestTests.m in Sources */ = {isa = PBXBuildFile; fileRef = CC7FD9E01BB5F750005CCB2B /* ASPhotosFrameworkImageRequestTests.m */; }; CC7FD9E21BB603FF005CCB2B /* ASPhotosFrameworkImageRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = CC7FD9DC1BB5E962005CCB2B /* ASPhotosFrameworkImageRequest.h */; settings = {ATTRIBUTES = (Public, ); }; }; + CCF18FF41D2575E300DF5895 /* NSIndexSet+ASHelpers.h in Headers */ = {isa = PBXBuildFile; fileRef = CC4981BA1D1C7F65004E13CC /* NSIndexSet+ASHelpers.h */; }; D785F6621A74327E00291744 /* ASScrollNode.h in Headers */ = {isa = PBXBuildFile; fileRef = D785F6601A74327E00291744 /* ASScrollNode.h */; settings = {ATTRIBUTES = (Public, ); }; }; D785F6631A74327E00291744 /* ASScrollNode.m in Sources */ = {isa = PBXBuildFile; fileRef = D785F6611A74327E00291744 /* ASScrollNode.m */; }; DB55C2611C6408D6004EDCF5 /* _ASTransitionContext.h in Headers */ = {isa = PBXBuildFile; fileRef = DB55C25F1C6408D6004EDCF5 /* _ASTransitionContext.h */; }; @@ -1799,6 +1800,7 @@ 254C6B741BF94DF4003EC431 /* ASTextNodeWordKerner.h in Headers */, DB55C2671C641AE4004EDCF5 /* ASContextTransitioning.h in Headers */, 68B0277B1C1A79D60041016B /* ASDisplayNode+Beta.h in Headers */, + CCF18FF41D2575E300DF5895 /* NSIndexSet+ASHelpers.h in Headers */, B350622D1B010EFD0018CF92 /* ASScrollDirection.h in Headers */, 254C6B751BF94DF4003EC431 /* ASTextKitComponents.h in Headers */, B35062081B010EFD0018CF92 /* ASScrollNode.h in Headers */, From 8804342a9863984774f3089f8669789de69f9293 Mon Sep 17 00:00:00 2001 From: Michael Schneider Date: Thu, 30 Jun 2016 19:44:40 -0700 Subject: [PATCH 35/43] Don't propagate trait collections to cells if the node is not loaded yet (#1833) This fixes an issue where the propagation of trait collections trigger are creation of the node if the node view was not loaded yet. --- AsyncDisplayKit/Details/ASEnvironment.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/AsyncDisplayKit/Details/ASEnvironment.h b/AsyncDisplayKit/Details/ASEnvironment.h index e267de1e8a..dd95c2e107 100644 --- a/AsyncDisplayKit/Details/ASEnvironment.h +++ b/AsyncDisplayKit/Details/ASEnvironment.h @@ -157,6 +157,10 @@ ASDISPLAYNODE_EXTERN_C_END ASDN::MutexLocker l(lock);\ ASEnvironmentTraitCollection oldTraits = self.environmentState.environmentTraitCollection;\ [super setEnvironmentState:environmentState];\ +\ + /* Extra Trait Collection Handling */\ + /* If the node is not loaded yet don't do anything as otherwise the access of the view will trigger a load*/\ + if (!self.isNodeLoaded) { return; } \ ASEnvironmentTraitCollection currentTraits = environmentState.environmentTraitCollection;\ if (ASEnvironmentTraitCollectionIsEqualToASEnvironmentTraitCollection(currentTraits, oldTraits) == NO) {\ /* Must dispatch to main for self.view && [self.view.dataController completedNodes]*/ \ From 8c3025bb12fa09f692a7015627140cf66bdb0ef9 Mon Sep 17 00:00:00 2001 From: ricky Date: Thu, 30 Jun 2016 19:45:29 -0700 Subject: [PATCH 36/43] [ASDisplayNode] added asyncTraitCollectionDidChange method (#1831) Subclasses can override this method to react to a trait collection change --- AsyncDisplayKit.xcodeproj/project.pbxproj | 2 ++ AsyncDisplayKit/ASDisplayNode+Subclasses.h | 7 +++++++ AsyncDisplayKit/ASDisplayNode.mm | 15 ++++++++++++++- 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/AsyncDisplayKit.xcodeproj/project.pbxproj b/AsyncDisplayKit.xcodeproj/project.pbxproj index 3e23e8b999..871b580764 100644 --- a/AsyncDisplayKit.xcodeproj/project.pbxproj +++ b/AsyncDisplayKit.xcodeproj/project.pbxproj @@ -368,6 +368,7 @@ 9C8898BB1C738B9800D6B02E /* ASTextKitFontSizeAdjuster.mm in Sources */ = {isa = PBXBuildFile; fileRef = 9C8898BA1C738B9800D6B02E /* ASTextKitFontSizeAdjuster.mm */; }; 9C8898BC1C738BA800D6B02E /* ASTextKitFontSizeAdjuster.mm in Sources */ = {isa = PBXBuildFile; fileRef = 9C8898BA1C738B9800D6B02E /* ASTextKitFontSizeAdjuster.mm */; }; 9C8898BD1C738BB800D6B02E /* ASTextKitFontSizeAdjuster.h in Headers */ = {isa = PBXBuildFile; fileRef = A32FEDD31C501B6A004F642A /* ASTextKitFontSizeAdjuster.h */; }; + 9CC606651D24DF9E006581A0 /* NSIndexSet+ASHelpers.m in Sources */ = {isa = PBXBuildFile; fileRef = CC4981BB1D1C7F65004E13CC /* NSIndexSet+ASHelpers.m */; }; 9CDC18CC1B910E12004965E2 /* ASLayoutablePrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 9CDC18CB1B910E12004965E2 /* ASLayoutablePrivate.h */; settings = {ATTRIBUTES = (Public, ); }; }; 9CDC18CD1B910E12004965E2 /* ASLayoutablePrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 9CDC18CB1B910E12004965E2 /* ASLayoutablePrivate.h */; settings = {ATTRIBUTES = (Public, ); }; }; 9CFFC6BE1CCAC52B006A6476 /* ASEnvironment.mm in Sources */ = {isa = PBXBuildFile; fileRef = 9CFFC6BD1CCAC52B006A6476 /* ASEnvironment.mm */; }; @@ -2276,6 +2277,7 @@ CC3B208C1C3F7A5400798563 /* ASWeakSet.m in Sources */, B350621C1B010EFD0018CF92 /* ASFlowLayoutController.mm in Sources */, B350621E1B010EFD0018CF92 /* ASHighlightOverlayLayer.mm in Sources */, + 9CC606651D24DF9E006581A0 /* NSIndexSet+ASHelpers.m in Sources */, 92074A641CC8BA1900918F75 /* ASImageNode+tvOS.m in Sources */, B35062541B010EFD0018CF92 /* ASImageNode+CGExtras.m in Sources */, 68355B401CB57A69001D4E68 /* ASImageContainerProtocolCategories.m in Sources */, diff --git a/AsyncDisplayKit/ASDisplayNode+Subclasses.h b/AsyncDisplayKit/ASDisplayNode+Subclasses.h index 967b82270d..9711355757 100644 --- a/AsyncDisplayKit/ASDisplayNode+Subclasses.h +++ b/AsyncDisplayKit/ASDisplayNode+Subclasses.h @@ -465,6 +465,13 @@ NS_ASSUME_NONNULL_BEGIN */ - (NSString *)descriptionForRecursiveDescription; +/** + * @abstract Called when the node's ASTraitCollection changes + * + * @discussion Subclasses can override this method to react to a trait collection change. + */ +- (void)asyncTraitCollectionDidChange; + @end #define ASDisplayNodeAssertThreadAffinity(viewNode) ASDisplayNodeAssert(!viewNode || ASDisplayNodeThreadIsMain() || !(viewNode).nodeLoaded, @"Incorrect display node thread affinity - this method should not be called off the main thread after the ASDisplayNode's view or layer have been created") diff --git a/AsyncDisplayKit/ASDisplayNode.mm b/AsyncDisplayKit/ASDisplayNode.mm index e38731e7f8..ffda3fa232 100644 --- a/AsyncDisplayKit/ASDisplayNode.mm +++ b/AsyncDisplayKit/ASDisplayNode.mm @@ -2755,7 +2755,12 @@ static const char *ASDisplayNodeDrawingPriorityKey = "ASDrawingPriority"; - (void)setEnvironmentState:(ASEnvironmentState)environmentState { + ASEnvironmentTraitCollection oldTraitCollection = _environmentState.environmentTraitCollection; _environmentState = environmentState; + + if (ASEnvironmentTraitCollectionIsEqualToASEnvironmentTraitCollection(oldTraitCollection, _environmentState.environmentTraitCollection) == NO) { + [self asyncTraitCollectionDidChange]; + } } - (ASDisplayNode *)parent @@ -2785,7 +2790,10 @@ static const char *ASDisplayNodeDrawingPriorityKey = "ASDrawingPriority"; - (void)setEnvironmentTraitCollection:(ASEnvironmentTraitCollection)environmentTraitCollection { - _environmentState.environmentTraitCollection = environmentTraitCollection; + if (ASEnvironmentTraitCollectionIsEqualToASEnvironmentTraitCollection(environmentTraitCollection, _environmentState.environmentTraitCollection) == NO) { + _environmentState.environmentTraitCollection = environmentTraitCollection; + [self asyncTraitCollectionDidChange]; + } } ASEnvironmentLayoutOptionsForwarding @@ -2797,6 +2805,11 @@ ASEnvironmentLayoutExtensibilityForwarding return [ASTraitCollection traitCollectionWithASEnvironmentTraitCollection:self.environmentTraitCollection]; } +- (void)asyncTraitCollectionDidChange +{ + +} + #if TARGET_OS_TV #pragma mark - UIFocusEnvironment Protocol (tvOS) From 09a344b669dec2fd5ea66ce9105cdca647afec28 Mon Sep 17 00:00:00 2001 From: Gareth Reese Date: Fri, 1 Jul 2016 15:15:10 +0100 Subject: [PATCH 37/43] [ASVideoPlayerNode] Expose the placeholder image for the video player node --- AsyncDisplayKit/ASVideoPlayerNode.h | 1 + AsyncDisplayKit/ASVideoPlayerNode.mm | 13 +++++++++++++ 2 files changed, 14 insertions(+) diff --git a/AsyncDisplayKit/ASVideoPlayerNode.h b/AsyncDisplayKit/ASVideoPlayerNode.h index de07dada8e..c8f65fcb80 100644 --- a/AsyncDisplayKit/ASVideoPlayerNode.h +++ b/AsyncDisplayKit/ASVideoPlayerNode.h @@ -49,6 +49,7 @@ NS_ASSUME_NONNULL_BEGIN @property (nonatomic, assign, readwrite) BOOL muted; @property (nonatomic, assign, readonly) ASVideoNodePlayerState playerState; @property (nonatomic, assign, readwrite) BOOL shouldAggressivelyRecoverFromStall; +@property (nullable, atomic, strong, readwrite) NSURL *placeholderImageURL; //! Defaults to 100 @property (nonatomic, assign) int32_t periodicTimeObserverTimescale; diff --git a/AsyncDisplayKit/ASVideoPlayerNode.mm b/AsyncDisplayKit/ASVideoPlayerNode.mm index cd880bcd4d..fd76f79d30 100644 --- a/AsyncDisplayKit/ASVideoPlayerNode.mm +++ b/AsyncDisplayKit/ASVideoPlayerNode.mm @@ -76,6 +76,9 @@ static void *ASVideoPlayerNodeContext = &ASVideoPlayerNodeContext; @end @implementation ASVideoPlayerNode + +@dynamic placeholderImageURL; + - (instancetype)init { if (!(self = [super init])) { @@ -771,6 +774,16 @@ static void *ASVideoPlayerNodeContext = &ASVideoPlayerNodeContext; return _videoNode.shouldAggressivelyRecoverFromStall; } +- (void) setPlaceholderImageURL:(NSURL *)placeholderImageURL +{ + _videoNode.URL = placeholderImageURL; +} + +- (NSURL*) placeholderImageURL +{ + return _videoNode.URL; +} + - (void)setShouldAggressivelyRecoverFromStall:(BOOL)shouldAggressivelyRecoverFromStall { if (_shouldAggressivelyRecoverFromStall == shouldAggressivelyRecoverFromStall) { From b1ceab7a61ec277a20b5d8df302e0b522890b227 Mon Sep 17 00:00:00 2001 From: Levi McCallum Date: Fri, 1 Jul 2016 09:39:36 -0700 Subject: [PATCH 38/43] Add nodeForPageAtIndex: to header and clean up doc --- AsyncDisplayKit/ASPagerNode.h | 47 +++++++++++++++++++++-------------- 1 file changed, 29 insertions(+), 18 deletions(-) diff --git a/AsyncDisplayKit/ASPagerNode.h b/AsyncDisplayKit/ASPagerNode.h index 2f9809da79..cbef217812 100644 --- a/AsyncDisplayKit/ASPagerNode.h +++ b/AsyncDisplayKit/ASPagerNode.h @@ -22,8 +22,6 @@ * This method replaces -collectionView:numberOfItemsInSection: * * @param pagerNode The sender. - * - * * @returns The total number of pages that can display in the pagerNode. */ - (NSInteger)numberOfPagesInPagerNode:(ASPagerNode *)pagerNode; @@ -34,9 +32,7 @@ * This method replaces -collectionView:nodeForItemAtIndexPath: * * @param pagerNode The sender. - * - * @param index The index of the requested node. - * + * @param index The index of the requested node. * @returns a node for display at this index. This will be called on the main thread and should * not implement reuse (it will be called once per row). Unlike UICollectionView's version, * this method is not called when the row is about to display. @@ -48,9 +44,7 @@ * This method takes precedence over pagerNode:nodeAtIndex: if implemented. * * @param pagerNode The sender. - * - * @param index The index of the requested node. - * + * @param index The index of the requested node. * @returns a block that creates the node for display at this index. * Must be thread-safe (can be called on the main thread or a background * queue) and should not implement reuse (it will be called once per row). @@ -61,9 +55,7 @@ * Provides the constrained size range for measuring the node at the index path. * * @param pagerNode The sender. - * * @param indexPath The index path of the node. - * * @returns A constrained size range for layout the node at this index path. */ - (ASSizeRange)pagerNode:(ASPagerNode *)pagerNode constrainedSizeForNodeAtIndexPath:(NSIndexPath *)indexPath; @@ -76,27 +68,46 @@ @interface ASPagerNode : ASCollectionNode -/// Configures a default horizontal, paging flow layout with 0 inter-item spacing. +/** + * Configures a default horizontal, paging flow layout with 0 inter-item spacing. + */ - (instancetype)init; -/// Initializer with custom-configured flow layout properties. +/** + * Initializer with custom-configured flow layout properties. + */ - (instancetype)initWithCollectionViewLayout:(ASPagerFlowLayout *)flowLayout; -/// Data Source is required, and uses a different protocol from ASCollectionNode. +/** + * Data Source is required, and uses a different protocol from ASCollectionNode. + */ - (void)setDataSource:(id )dataSource; - (id )dataSource; -// Delegate is optional, and uses the same protocol as ASCollectionNode. -// This includes UIScrollViewDelegate as well as most methods from UICollectionViewDelegate, like willDisplay... +/** + * Delegate is optional, and uses the same protocol as ASCollectionNode. + * This includes UIScrollViewDelegate as well as most methods from UICollectionViewDelegate, like willDisplay... + */ @property (nonatomic, weak) id delegate; -/// The underlying ASCollectionView object. +/** + * The underlying ASCollectionView object. + */ @property (nonatomic, readonly) ASCollectionView *view; -/// Returns the current page index +/** + * Returns the current page index + */ @property (nonatomic, assign, readonly) NSInteger currentPageIndex; -/// Scroll the contents of the receiver to ensure that the page is visible +/** + * Scroll the contents of the receiver to ensure that the page is visible + */ - (void)scrollToPageAtIndex:(NSInteger)index animated:(BOOL)animated; +/** + * Returns the node for the passed page index + */ +- (ASCellNode *)nodeForPageAtIndex:(NSInteger)index; + @end From 53bc126ae59bf3691bcb85be9e2978b93f7a7554 Mon Sep 17 00:00:00 2001 From: Levi McCallum Date: Fri, 1 Jul 2016 09:42:39 -0700 Subject: [PATCH 39/43] Add implementation of nodeForPageAtIndex: --- AsyncDisplayKit/ASPagerNode.m | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/AsyncDisplayKit/ASPagerNode.m b/AsyncDisplayKit/ASPagerNode.m index 2c6cd4b32e..c266ef18f3 100644 --- a/AsyncDisplayKit/ASPagerNode.m +++ b/AsyncDisplayKit/ASPagerNode.m @@ -98,6 +98,11 @@ [self.view scrollToItemAtIndexPath:indexPath atScrollPosition:UICollectionViewScrollPositionLeft animated:animated]; } +- (ASCellNode *)nodeForPageAtIndex:(NSInteger)index +{ + return [self.view nodeForItemAtIndexPath:[NSIndexPath indexPathForItem:index inSection:0]]; +} + #pragma mark - ASCollectionViewDataSource - (ASCellNodeBlock)collectionView:(ASCollectionView *)collectionView nodeBlockForItemAtIndexPath:(NSIndexPath *)indexPath From ebaa2c157e7c1b047d6434705132e5adee881f74 Mon Sep 17 00:00:00 2001 From: Adlai Holler Date: Fri, 1 Jul 2016 11:47:05 -0700 Subject: [PATCH 40/43] Remove aggregate CGRect initializers in ASDataController --- AsyncDisplayKit/Details/ASDataController.mm | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/AsyncDisplayKit/Details/ASDataController.mm b/AsyncDisplayKit/Details/ASDataController.mm index 163b812e10..f9a890e609 100644 --- a/AsyncDisplayKit/Details/ASDataController.mm +++ b/AsyncDisplayKit/Details/ASDataController.mm @@ -143,8 +143,9 @@ static void *kASSizingQueueContext = &kASSizingQueueContext; */ - (void)_layoutNode:(ASCellNode *)node withConstrainedSize:(ASSizeRange)constrainedSize { - CGSize size = [node measureWithSizeRange:constrainedSize].size; - node.frame = { .size = size }; + CGRect frame = CGRectZero; + frame.size = [node measureWithSizeRange:constrainedSize].size; + node.frame = frame; } /** @@ -849,8 +850,9 @@ static void *kASSizingQueueContext = &kASSizingQueueContext; for (ASCellNode *node in section) { NSIndexPath *indexPath = [NSIndexPath indexPathForRow:rowIndex inSection:sectionIndex]; ASSizeRange constrainedSize = [self constrainedSizeForNodeOfKind:kind atIndexPath:indexPath]; - CGSize size = [node measureWithSizeRange:constrainedSize].size; - node.frame = { .size = size }; + CGRect frame = CGRectZero; + frame.size = [node measureWithSizeRange:constrainedSize].size; + node.frame = frame; rowIndex += 1; } sectionIndex += 1; From 9501299eed1d450ef5f9b62db4495fc871c052a0 Mon Sep 17 00:00:00 2001 From: Michael Schneider Date: Fri, 24 Jun 2016 07:57:20 -0700 Subject: [PATCH 41/43] Use flags to cache instead of instance variables for caching respond to selector calls --- AsyncDisplayKit/ASNetworkImageNode.mm | 84 ++++++++++++++------------- 1 file changed, 44 insertions(+), 40 deletions(-) diff --git a/AsyncDisplayKit/ASNetworkImageNode.mm b/AsyncDisplayKit/ASNetworkImageNode.mm index fbfea44213..77559209c0 100755 --- a/AsyncDisplayKit/ASNetworkImageNode.mm +++ b/AsyncDisplayKit/ASNetworkImageNode.mm @@ -43,24 +43,28 @@ static const CGSize kMinReleaseImageOnBackgroundSize = {20.0, 20.0}; BOOL _imageLoaded; CGFloat _currentImageQuality; CGFloat _renderedImageQuality; - - // TODO: Move this to flags - BOOL _delegateSupportsDidStartFetchingData; - BOOL _delegateSupportsDidFailWithError; - BOOL _delegateSupportsDidFinishDecoding; - BOOL _delegateSupportsDidLoadImage; - BOOL _shouldRenderProgressImages; - //set on init only - BOOL _downloaderSupportsNewProtocol; - BOOL _downloaderImplementsSetProgress; - BOOL _downloaderImplementsSetPriority; - BOOL _downloaderImplementsAnimatedImage; + struct { + unsigned int delegateDidStartFetchingData:1; + unsigned int delegateDidFailWithError:1; + unsigned int delegateDidFinishDecoding:1; + unsigned int delegateDidLoadImage:1; + } _delegateFlags; - BOOL _cacheSupportsNewProtocol; - BOOL _cacheSupportsClearing; - BOOL _cacheSupportsSynchronousFetch; + //set on init only + struct { + unsigned int downloaderSupportsNewProtocol:1; + unsigned int downloaderImplementsSetProgress:1; + unsigned int downloaderImplementsSetPriority:1; + unsigned int downloaderImplementsAnimatedImage:1; + } _downloaderFlags; + + struct { + unsigned int cacheSupportsNewProtocol:1; + unsigned int cacheSupportsClearing:1; + unsigned int cacheSupportsSynchronousFetch:1; + } _cacheFlags; } @end @@ -76,17 +80,17 @@ static const CGSize kMinReleaseImageOnBackgroundSize = {20.0, 20.0}; ASDisplayNodeAssert([downloader respondsToSelector:@selector(downloadImageWithURL:callbackQueue:downloadProgress:completion:)] || [downloader respondsToSelector:@selector(downloadImageWithURL:callbackQueue:downloadProgressBlock:completion:)], @"downloader must respond to either downloadImageWithURL:callbackQueue:downloadProgress:completion: or downloadImageWithURL:callbackQueue:downloadProgressBlock:completion:."); - _downloaderSupportsNewProtocol = [downloader respondsToSelector:@selector(downloadImageWithURL:callbackQueue:downloadProgress:completion:)]; + _downloaderFlags.downloaderSupportsNewProtocol = [downloader respondsToSelector:@selector(downloadImageWithURL:callbackQueue:downloadProgress:completion:)]; ASDisplayNodeAssert(cache == nil || [cache respondsToSelector:@selector(cachedImageWithURL:callbackQueue:completion:)] || [cache respondsToSelector:@selector(fetchCachedImageWithURL:callbackQueue:completion:)], @"cacher must respond to either cachedImageWithURL:callbackQueue:completion: or fetchCachedImageWithURL:callbackQueue:completion:"); - _downloaderImplementsSetProgress = [downloader respondsToSelector:@selector(setProgressImageBlock:callbackQueue:withDownloadIdentifier:)]; - _downloaderImplementsSetPriority = [downloader respondsToSelector:@selector(setPriority:withDownloadIdentifier:)]; - _downloaderImplementsAnimatedImage = [downloader respondsToSelector:@selector(animatedImageWithData:)]; + _downloaderFlags.downloaderImplementsSetProgress = [downloader respondsToSelector:@selector(setProgressImageBlock:callbackQueue:withDownloadIdentifier:)]; + _downloaderFlags.downloaderImplementsSetPriority = [downloader respondsToSelector:@selector(setPriority:withDownloadIdentifier:)]; + _downloaderFlags.downloaderImplementsAnimatedImage = [downloader respondsToSelector:@selector(animatedImageWithData:)]; - _cacheSupportsNewProtocol = [cache respondsToSelector:@selector(cachedImageWithURL:callbackQueue:completion:)]; - _cacheSupportsClearing = [cache respondsToSelector:@selector(clearFetchedImageFromCacheWithURL:)]; - _cacheSupportsSynchronousFetch = [cache respondsToSelector:@selector(synchronouslyFetchedCachedImageWithURL:)]; + _cacheFlags.cacheSupportsNewProtocol = [cache respondsToSelector:@selector(cachedImageWithURL:callbackQueue:completion:)]; + _cacheFlags.cacheSupportsClearing = [cache respondsToSelector:@selector(clearFetchedImageFromCacheWithURL:)]; + _cacheFlags.cacheSupportsSynchronousFetch = [cache respondsToSelector:@selector(synchronouslyFetchedCachedImageWithURL:)]; _shouldCacheImage = YES; _shouldRenderProgressImages = YES; @@ -214,10 +218,10 @@ static const CGSize kMinReleaseImageOnBackgroundSize = {20.0, 20.0}; ASDN::MutexLocker l(_lock); _delegate = delegate; - _delegateSupportsDidStartFetchingData = [delegate respondsToSelector:@selector(imageNodeDidStartFetchingData:)]; - _delegateSupportsDidFailWithError = [delegate respondsToSelector:@selector(imageNode:didFailWithError:)]; - _delegateSupportsDidFinishDecoding = [delegate respondsToSelector:@selector(imageNodeDidFinishDecoding:)]; - _delegateSupportsDidLoadImage = [delegate respondsToSelector:@selector(imageNode:didLoadImage:)]; + _delegateFlags.delegateDidStartFetchingData = [delegate respondsToSelector:@selector(imageNodeDidStartFetchingData:)]; + _delegateFlags.delegateDidFailWithError = [delegate respondsToSelector:@selector(imageNode:didFailWithError:)]; + _delegateFlags.delegateDidFinishDecoding = [delegate respondsToSelector:@selector(imageNodeDidFinishDecoding:)]; + _delegateFlags.delegateDidLoadImage = [delegate respondsToSelector:@selector(imageNode:didLoadImage:)]; } - (id)delegate @@ -258,7 +262,7 @@ static const CGSize kMinReleaseImageOnBackgroundSize = {20.0, 20.0}; { [super displayWillStart]; - if (_cacheSupportsSynchronousFetch) { + if (_cacheFlags.cacheSupportsSynchronousFetch) { ASDN::MutexLocker l(_lock); if (_imageLoaded == NO && _URL && _downloadIdentifier == nil) { UIImage *result = [[_cache synchronouslyFetchedCachedImageWithURL:_URL] asdk_image]; @@ -275,7 +279,7 @@ static const CGSize kMinReleaseImageOnBackgroundSize = {20.0, 20.0}; // TODO: Consider removing this; it predates ASInterfaceState, which now ensures that even non-range-managed nodes get a -fetchData call. [self fetchData]; - if (self.image == nil && _downloaderImplementsSetPriority) { + if (self.image == nil && _downloaderFlags.downloaderImplementsSetPriority) { ASDN::MutexLocker l(_lock); if (_downloadIdentifier != nil) { [_downloader setPriority:ASImageDownloaderPriorityImminent withDownloadIdentifier:_downloadIdentifier]; @@ -289,7 +293,7 @@ static const CGSize kMinReleaseImageOnBackgroundSize = {20.0, 20.0}; { [super visibleStateDidChange:isVisible]; - if (_downloaderImplementsSetPriority) { + if (_downloaderFlags.downloaderImplementsSetPriority) { _lock.lock(); if (_downloadIdentifier != nil) { if (isVisible) { @@ -314,7 +318,7 @@ static const CGSize kMinReleaseImageOnBackgroundSize = {20.0, 20.0}; [self _cancelImageDownload]; [self _clearImage]; - if (_cacheSupportsClearing) { + if (_cacheFlags.cacheSupportsClearing) { [_cache clearFetchedImageFromCacheWithURL:_URL]; } } @@ -344,7 +348,7 @@ static const CGSize kMinReleaseImageOnBackgroundSize = {20.0, 20.0}; ASInterfaceState interfaceState = self.interfaceState; ASDN::MutexLocker l(_lock); - if (!_downloaderImplementsSetProgress || _downloadIdentifier == nil) { + if (!_downloaderFlags.downloaderImplementsSetProgress || _downloadIdentifier == nil) { return; } @@ -411,7 +415,7 @@ static const CGSize kMinReleaseImageOnBackgroundSize = {20.0, 20.0}; { ASPerformBlockOnBackgroundThread(^{ _lock.lock(); - if (_downloaderSupportsNewProtocol) { + if (_downloaderFlags.downloaderSupportsNewProtocol) { _downloadIdentifier = [_downloader downloadImageWithURL:_URL callbackQueue:dispatch_get_main_queue() downloadProgress:NULL @@ -447,7 +451,7 @@ static const CGSize kMinReleaseImageOnBackgroundSize = {20.0, 20.0}; if (!_imageLoaded && _URL != nil && _downloadIdentifier == nil) { { ASDN::MutexLocker l(_lock); - if (_delegateSupportsDidStartFetchingData) { + if (_delegateFlags.delegateDidStartFetchingData) { [_delegate imageNodeDidStartFetchingData:self]; } } @@ -474,7 +478,7 @@ static const CGSize kMinReleaseImageOnBackgroundSize = {20.0, 20.0}; // If the file may be an animated gif and then created an animated image. id animatedImage = nil; - if (_downloaderImplementsAnimatedImage) { + if (_downloaderFlags.downloaderImplementsAnimatedImage) { NSData *data = [NSData dataWithContentsOfURL:_URL]; animatedImage = [_downloader animatedImageWithData:data]; @@ -497,7 +501,7 @@ static const CGSize kMinReleaseImageOnBackgroundSize = {20.0, 20.0}; dispatch_async(dispatch_get_main_queue(), ^{ self.currentImageQuality = 1.0; }); - if (_delegateSupportsDidLoadImage) { + if (_delegateFlags.delegateDidLoadImage) { [_delegate imageNode:self didLoadImage:self.image]; } }); @@ -519,7 +523,7 @@ static const CGSize kMinReleaseImageOnBackgroundSize = {20.0, 20.0}; if (imageContainer != nil) { strongSelf->_imageLoaded = YES; - if ([imageContainer asdk_animatedImageData] && _downloaderImplementsAnimatedImage) { + if ([imageContainer asdk_animatedImageData] && _downloaderFlags.downloaderImplementsAnimatedImage) { strongSelf.animatedImage = [_downloader animatedImageWithData:[imageContainer asdk_animatedImageData]]; } else { strongSelf.image = [imageContainer asdk_image]; @@ -534,11 +538,11 @@ static const CGSize kMinReleaseImageOnBackgroundSize = {20.0, 20.0}; strongSelf->_cacheUUID = nil; if (imageContainer != nil) { - if (strongSelf->_delegateSupportsDidLoadImage) { + if (strongSelf->_delegateFlags.delegateDidLoadImage) { [strongSelf->_delegate imageNode:strongSelf didLoadImage:strongSelf.image]; } } - else if (error && strongSelf->_delegateSupportsDidFailWithError) { + else if (error && strongSelf->_delegateFlags.delegateDidFailWithError) { [strongSelf->_delegate imageNode:strongSelf didFailWithError:error]; } }; @@ -560,7 +564,7 @@ static const CGSize kMinReleaseImageOnBackgroundSize = {20.0, 20.0}; } }; - if (_cacheSupportsNewProtocol) { + if (_cacheFlags.cacheSupportsNewProtocol) { [_cache cachedImageWithURL:_URL callbackQueue:dispatch_get_main_queue() completion:cacheCompletion]; @@ -588,7 +592,7 @@ static const CGSize kMinReleaseImageOnBackgroundSize = {20.0, 20.0}; [super displayDidFinish]; ASDN::MutexLocker l(_lock); - if (_delegateSupportsDidFinishDecoding && self.layer.contents != nil) { + if (_delegateFlags.delegateDidFinishDecoding && self.layer.contents != nil) { /* We store the image quality in _currentImageQuality whenever _image is set. On the following displayDidFinish, we'll know that _currentImageQuality is the quality of the image that has just finished rendering. In order for this to be accurate, we need to be sure we are on main thread when we set _currentImageQuality. Otherwise, it is possible for _currentImageQuality From d2d8b0a1cb2027bdcda171117ba5d6e811d02564 Mon Sep 17 00:00:00 2001 From: Scott Goodson Date: Fri, 1 Jul 2016 20:11:23 -0700 Subject: [PATCH 42/43] [ASDisplayNode] Adjust behavior of -removeFromSupernode to ensure "root" nodes are removed from their superview/superlayer. This situation is relatively uncommon. If a user manually uses -[UIView addSubnode:], the convenience category method, and then calls -[ASDisplayNode removeFromSuperview] -- we would bypass performing the actual removal as no supernode pointer is set. After further consideration, the special handling here to support divergence between the supernode pointer and the view / layer hierarchy is not something we need to maintain going forward, and removing it makes addressing this easy. --- AsyncDisplayKit/ASDisplayNode.mm | 21 +++++++-------------- AsyncDisplayKit/Details/_ASDisplayView.mm | 5 +++-- 2 files changed, 10 insertions(+), 16 deletions(-) diff --git a/AsyncDisplayKit/ASDisplayNode.mm b/AsyncDisplayKit/ASDisplayNode.mm index cf38ddd804..32b1c80b6a 100644 --- a/AsyncDisplayKit/ASDisplayNode.mm +++ b/AsyncDisplayKit/ASDisplayNode.mm @@ -1543,27 +1543,20 @@ static NSInteger incrementIfFound(NSInteger i) { __weak UIView *view = _view; __weak CALayer *layer = _layer; BOOL layerBacked = _flags.layerBacked; + BOOL isNodeLoaded = (layer != nil || view != nil); _propertyLock.unlock(); - - if (supernode == nil) { - return; - } + // Clear supernode's reference to us before removing the view from the hierarchy, as _ASDisplayView + // will trigger us to clear our _supernode pointer in willMoveToSuperview:nil. + // This may result in removing the last strong reference, triggering deallocation after this method. [supernode _removeSubnode:self]; - if (self.nodeLoaded && supernode.nodeLoaded) { - // Check to ensure that our view or layer is actually inside of our supernode; otherwise, don't remove it. - // Though _ASDisplayView decouples the supernode if it is inserted inside another view hierarchy, this is - // more difficult to guarantee with _ASDisplayLayer because CoreAnimation doesn't have a -didMoveToSuperlayer. + if (isNodeLoaded && (supernode == nil || supernode.isNodeLoaded)) { ASPerformBlockOnMainThread(^{ if (layerBacked || supernode.layerBacked) { - if (layer.superlayer == supernode.layer) { - [layer removeFromSuperlayer]; - } + [layer removeFromSuperlayer]; } else { - if (view.superview == supernode.view) { - [view removeFromSuperview]; - } + [view removeFromSuperview]; } }); } diff --git a/AsyncDisplayKit/Details/_ASDisplayView.mm b/AsyncDisplayKit/Details/_ASDisplayView.mm index ba0de48e0f..2d4deb5259 100644 --- a/AsyncDisplayKit/Details/_ASDisplayView.mm +++ b/AsyncDisplayKit/Details/_ASDisplayView.mm @@ -86,8 +86,7 @@ UIView *currentSuperview = self.superview; if (!currentSuperview && newSuperview) { self.keepalive_node = _node; - } - else if (currentSuperview && !newSuperview) { + } else if (currentSuperview && !newSuperview) { // Clearing keepalive_node may cause deallocation of the node. In this case, __exitHierarchy may not have an opportunity (e.g. _node will be cleared // by the time -didMoveToWindow occurs after this) to clear the Visible interfaceState, which we need to do before deallocation to meet an API guarantee. if (_node.inHierarchy) { @@ -95,6 +94,8 @@ } self.keepalive_node = nil; } + + ASDisplayNodeAssert(self.keepalive_node == nil || newSuperview != nil, @"Keepalive reference should not exist if there is no superview."); if (newSuperview) { ASDisplayNode *supernode = _node.supernode; From 9be2f1db4e05cfbd058ff441f8adfe4da076b133 Mon Sep 17 00:00:00 2001 From: Michael Schneider Date: Wed, 29 Jun 2016 11:20:24 -0700 Subject: [PATCH 43/43] Prevent calling endUpdatesAnimated:completion: in an unbalanced way --- .../Details/ASChangeSetDataController.m | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/AsyncDisplayKit/Details/ASChangeSetDataController.m b/AsyncDisplayKit/Details/ASChangeSetDataController.m index f6615d1bdb..3a31b8ce82 100644 --- a/AsyncDisplayKit/Details/ASChangeSetDataController.m +++ b/AsyncDisplayKit/Details/ASChangeSetDataController.m @@ -18,22 +18,19 @@ #import "ASDataController+Subclasses.h" -@interface ASChangeSetDataController () - -@property (nonatomic, assign) NSUInteger changeSetBatchUpdateCounter; -@property (nonatomic, strong) _ASHierarchyChangeSet *changeSet; - -@end - -@implementation ASChangeSetDataController +@implementation ASChangeSetDataController { + NSInteger _changeSetBatchUpdateCounter; + _ASHierarchyChangeSet *_changeSet; +} #pragma mark - Batching (External API) - (void)beginUpdates { ASDisplayNodeAssertMainThread(); - if (_changeSetBatchUpdateCounter == 0) { + if (_changeSetBatchUpdateCounter <= 0) { _changeSet = [_ASHierarchyChangeSet new]; + _changeSetBatchUpdateCounter = 0; } _changeSetBatchUpdateCounter++; } @@ -43,6 +40,9 @@ ASDisplayNodeAssertMainThread(); _changeSetBatchUpdateCounter--; + // Prevent calling endUpdatesAnimated:completion: in an unbalanced way + NSAssert(_changeSetBatchUpdateCounter >= 0, @"endUpdatesAnimated:completion: called without having a balanced beginUpdates call"); + if (_changeSetBatchUpdateCounter == 0) { [_changeSet markCompleted];