From e92a1360e78aed47056cb941517ff6339fc9a121 Mon Sep 17 00:00:00 2001 From: Scott Goodson Date: Thu, 14 Jan 2016 21:43:46 -0800 Subject: [PATCH 01/27] Ensure new ASPagerNode has a weak reference to the data source. --- AsyncDisplayKit/ASPagerNode.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AsyncDisplayKit/ASPagerNode.m b/AsyncDisplayKit/ASPagerNode.m index a69a963d..075d0f07 100644 --- a/AsyncDisplayKit/ASPagerNode.m +++ b/AsyncDisplayKit/ASPagerNode.m @@ -15,7 +15,7 @@ { UICollectionViewFlowLayout *_flowLayout; ASPagerNodeProxy *_proxy; - id _pagerDataSource; + __weak id _pagerDataSource; } @end From affb786a14d0767b334f277dbf2074dbeb56c79a Mon Sep 17 00:00:00 2001 From: Scott Goodson Date: Thu, 14 Jan 2016 23:12:01 -0800 Subject: [PATCH 02/27] [ASButtonNode] Pass through setDisplaysAsynchronously: to subnodes (image and title). --- AsyncDisplayKit/ASButtonNode.mm | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/AsyncDisplayKit/ASButtonNode.mm b/AsyncDisplayKit/ASButtonNode.mm index 500d8627..ae101c97 100644 --- a/AsyncDisplayKit/ASButtonNode.mm +++ b/AsyncDisplayKit/ASButtonNode.mm @@ -72,6 +72,13 @@ [self updateTitle]; } +- (void)setDisplaysAsynchronously:(BOOL)displaysAsynchronously +{ + [super setDisplaysAsynchronously:displaysAsynchronously]; + [self.imageNode setDisplaysAsynchronously:displaysAsynchronously]; + [self.titleNode setDisplaysAsynchronously:displaysAsynchronously]; +} + - (void)updateImage { ASDN::MutexLocker l(_propertyLock); From 6741ae658eec07dceb477cf84669692e668d88a7 Mon Sep 17 00:00:00 2001 From: Scott Goodson Date: Thu, 14 Jan 2016 23:28:15 -0800 Subject: [PATCH 03/27] [ASCellNode] Ensure we don't trigger the UIViewController to be created early if we are wrapping one. --- AsyncDisplayKit/ASCellNode.m | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/AsyncDisplayKit/ASCellNode.m b/AsyncDisplayKit/ASCellNode.m index 575200df..df7040d9 100644 --- a/AsyncDisplayKit/ASCellNode.m +++ b/AsyncDisplayKit/ASCellNode.m @@ -20,7 +20,6 @@ @interface ASCellNode () { - ASDisplayNodeDidLoadBlock _nodeLoadedBlock; UIViewController *_viewController; ASDisplayNode *_viewControllerNode; } @@ -49,15 +48,13 @@ ASDisplayNodeAssertNotNil(viewControllerBlock, @"should initialize with a valid block that returns a UIViewController"); if (viewControllerBlock) { - _viewController = viewControllerBlock(); - __weak UIViewController *weakViewController = _viewController; _viewControllerNode = [[ASDisplayNode alloc] initWithViewBlock:^UIView *{ - return weakViewController.view; + _viewController = viewControllerBlock(); + return _viewController.view; } didLoadBlock:didLoadBlock]; [self addSubnode:_viewControllerNode]; - _nodeLoadedBlock = didLoadBlock; } return self; From a6da3d185ad86c81a5b6933a2f9285b116b5fcb4 Mon Sep 17 00:00:00 2001 From: Matej Knopp Date: Mon, 28 Dec 2015 21:44:36 +0100 Subject: [PATCH 04/27] [ASCollectionView] prevent data controller from removing/adding sections during reloadDataImmediately Signed-off-by: Matej Knopp --- AsyncDisplayKit/ASCollectionView.mm | 1 + 1 file changed, 1 insertion(+) diff --git a/AsyncDisplayKit/ASCollectionView.mm b/AsyncDisplayKit/ASCollectionView.mm index a5f45469..2bea6002 100644 --- a/AsyncDisplayKit/ASCollectionView.mm +++ b/AsyncDisplayKit/ASCollectionView.mm @@ -252,6 +252,7 @@ static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell"; - (void)reloadDataImmediately { ASDisplayNodeAssertMainThread(); + _superIsPendingDataLoad = YES; [_dataController reloadDataImmediatelyWithAnimationOptions:kASCollectionViewAnimationNone]; [super reloadData]; } From 7821a0aa198f1b52b9535a12e658d2a235a5bd2a Mon Sep 17 00:00:00 2001 From: Aaron Schubert Date: Tue, 19 Jan 2016 11:43:03 +0000 Subject: [PATCH 05/27] Fixes bug #1077 --- AsyncDisplayKit/ASTableView.mm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AsyncDisplayKit/ASTableView.mm b/AsyncDisplayKit/ASTableView.mm index af0c9ddd..85da55f0 100644 --- a/AsyncDisplayKit/ASTableView.mm +++ b/AsyncDisplayKit/ASTableView.mm @@ -47,8 +47,8 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell"; - (void)layoutSubviews { - [_delegate willLayoutSubviewsOfTableViewCell:self]; [super layoutSubviews]; + [_delegate willLayoutSubviewsOfTableViewCell:self]; } - (void)didTransitionToState:(UITableViewCellStateMask)state From 10a2984d8c8326037fe046ae15daf1826a06bfe9 Mon Sep 17 00:00:00 2001 From: Aaron Schubert Date: Tue, 19 Jan 2016 12:25:30 +0000 Subject: [PATCH 06/27] Potential fix for #1076 --- AsyncDisplayKit/TextKit/ASTextKitRenderer.mm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AsyncDisplayKit/TextKit/ASTextKitRenderer.mm b/AsyncDisplayKit/TextKit/ASTextKitRenderer.mm index 7630c105..a978b0fc 100755 --- a/AsyncDisplayKit/TextKit/ASTextKitRenderer.mm +++ b/AsyncDisplayKit/TextKit/ASTextKitRenderer.mm @@ -111,7 +111,7 @@ static NSCharacterSet *_defaultAvoidTruncationCharacterSet() // to make sure our width calculations aren't being offset by glyphs going beyond the constrained rect. boundingRect = CGRectIntersection(boundingRect, {.size = constrainedRect.size}); - _calculatedSize = [_shadower outsetSizeWithInsetSize:boundingRect.size]; + _calculatedSize = [_shadower outsetSizeWithInsetSize:CGSizeMake(boundingRect.size.width + boundingRect.origin.x, boundingRect.size.height + boundingRect.origin.y)]; } - (CGSize)size From e972059f2388f7347295d3108e65f10119a8e10d Mon Sep 17 00:00:00 2001 From: Adlai Holler Date: Tue, 19 Jan 2016 10:28:04 -0800 Subject: [PATCH 07/27] Remove SpinLock because it's illegal in iOS --- AsyncDisplayKit/Details/ASThread.h | 33 ------------------------------ 1 file changed, 33 deletions(-) diff --git a/AsyncDisplayKit/Details/ASThread.h b/AsyncDisplayKit/Details/ASThread.h index 121756bc..38b534d3 100644 --- a/AsyncDisplayKit/Details/ASThread.h +++ b/AsyncDisplayKit/Details/ASThread.h @@ -195,39 +195,6 @@ namespace ASDN { typedef Locker StaticMutexLocker; typedef Unlocker StaticMutexUnlocker; - struct SpinLock - { - SpinLock &operator= (bool value) { - _l = value ? ~0 : 0; return *this; - } - - SpinLock() { _l = OS_SPINLOCK_INIT; } - SpinLock(const SpinLock&) = delete; - SpinLock &operator=(const SpinLock&) = delete; - - bool try_lock () { - return OSSpinLockTry (&_l); - } - - void lock () { - OSSpinLockLock(&_l); - } - - void unlock () { - OSSpinLockUnlock(&_l); - } - - OSSpinLock *spinlock () { - return &_l; - } - - private: - OSSpinLock _l; - }; - - typedef Locker SpinLocker; - typedef Unlocker SpinUnlocker; - struct Condition { Condition () { From 995f437e12509e03a6fb55d9b8298276a1f11459 Mon Sep 17 00:00:00 2001 From: Luke Zhao Date: Thu, 14 Jan 2016 17:53:08 -0800 Subject: [PATCH 08/27] Allow ASEditableTextNode to scroll --- AsyncDisplayKit/ASEditableTextNode.h | 5 ++++ AsyncDisplayKit/ASEditableTextNode.mm | 34 ++++++++++++++++++++++----- 2 files changed, 33 insertions(+), 6 deletions(-) diff --git a/AsyncDisplayKit/ASEditableTextNode.h b/AsyncDisplayKit/ASEditableTextNode.h index 983bfcd6..af2c17dd 100644 --- a/AsyncDisplayKit/ASEditableTextNode.h +++ b/AsyncDisplayKit/ASEditableTextNode.h @@ -23,6 +23,11 @@ NS_ASSUME_NONNULL_BEGIN #pragma mark - Configuration +/** + @abstract Enable scrolling on the textView + */ +@property (nonatomic) BOOL scrollEnabled; + /** @abstract Access to underlying UITextView for more configuration options. @warning This property should only be used on the main thread and should not be accessed before the editable text node's view is created. diff --git a/AsyncDisplayKit/ASEditableTextNode.mm b/AsyncDisplayKit/ASEditableTextNode.mm index 13554d88..d27695a4 100644 --- a/AsyncDisplayKit/ASEditableTextNode.mm +++ b/AsyncDisplayKit/ASEditableTextNode.mm @@ -16,16 +16,31 @@ #import "ASTextNodeWordKerner.h" #import "ASThread.h" -//! @abstract This subclass exists solely to ensure the text view's panGestureRecognizer never begins, because it's sporadically enabled by UITextView. It will be removed pending rdar://14729288. -@interface _ASDisabledPanUITextView : UITextView +//! @abstract This subclass forces the parent UITextView's scrollEnabled property to always be true. Instead, it disables the panGestureRecognizer when scrollEnabled is set to false. This ensures that the contentSize is caculated correctly. +//! See issue: https://github.com/facebook/AsyncDisplayKit/issues/1063 +@interface ASPanningOverriddenUITextView : UITextView +{ + BOOL _shouldBlockPanGesture; +} @end -@implementation _ASDisabledPanUITextView +@implementation ASPanningOverriddenUITextView + +- (BOOL)scrollEnabled +{ + return _shouldBlockPanGesture; +} + +- (void)setScrollEnabled:(BOOL)scrollEnabled +{ + _shouldBlockPanGesture = !scrollEnabled; + [super setScrollEnabled:YES]; +} - (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer { - // Never allow our pans to begin. - if (gestureRecognizer == self.panGestureRecognizer) + // Never allow our pans to begin when _shouldBlockPanGesture is true. + if (_shouldBlockPanGesture && gestureRecognizer == self.panGestureRecognizer) return NO; // Otherwise, proceed as usual. @@ -207,11 +222,18 @@ #pragma mark - Configuration @synthesize delegate = _delegate; +- (void)setScrollEnabled:(BOOL)scrollEnabled +{ + ASDN::MutexLocker l(_textKitLock); + _scrollEnabled = scrollEnabled; + [_textKitComponents.textView setScrollEnabled:_scrollEnabled]; +} + - (UITextView *)textView { ASDisplayNodeAssertMainThread(); if (!_textKitComponents.textView) { - _textKitComponents.textView = [[_ASDisabledPanUITextView alloc] initWithFrame:CGRectZero textContainer:_textKitComponents.textContainer]; + _textKitComponents.textView = [[ASPanningOverriddenUITextView alloc] initWithFrame:CGRectZero textContainer:_textKitComponents.textContainer]; } return _textKitComponents.textView; } From b989be6499635f85f73b8d14698eb3418ced3e31 Mon Sep 17 00:00:00 2001 From: Scott Goodson Date: Tue, 19 Jan 2016 18:30:01 -0800 Subject: [PATCH 09/27] Restore full functionality of the display / data ranges when not using the Node variants of Table / Collection. --- AsyncDisplayKit/ASCollectionView.mm | 10 +++++++++- AsyncDisplayKit/ASTableView.mm | 10 +++++++++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/AsyncDisplayKit/ASCollectionView.mm b/AsyncDisplayKit/ASCollectionView.mm index 2bea6002..5e8b7c03 100644 --- a/AsyncDisplayKit/ASCollectionView.mm +++ b/AsyncDisplayKit/ASCollectionView.mm @@ -801,7 +801,15 @@ static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell"; - (ASInterfaceState)interfaceStateForRangeController:(ASRangeController *)rangeController { - return self.collectionNode.interfaceState; + ASCollectionNode *collectionNode = self.collectionNode; + if (collectionNode) { + return self.collectionNode.interfaceState; + } else { + // Until we can always create an associated ASCollectionNode without a retain cycle, + // we might be on our own to try to guess if we're visible. The node normally + // handles this even if it is the root / directly added to the view hierarchy. + return (self.window != nil ? ASInterfaceStateVisible : ASInterfaceStateNone); + } } - (NSArray *)rangeController:(ASRangeController *)rangeController nodesAtIndexPaths:(NSArray *)indexPaths diff --git a/AsyncDisplayKit/ASTableView.mm b/AsyncDisplayKit/ASTableView.mm index af0c9ddd..289fdc29 100644 --- a/AsyncDisplayKit/ASTableView.mm +++ b/AsyncDisplayKit/ASTableView.mm @@ -722,7 +722,15 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell"; - (ASInterfaceState)interfaceStateForRangeController:(ASRangeController *)rangeController { - return self.tableNode.interfaceState; + ASTableNode *tableNode = self.tableNode; + if (tableNode) { + return self.tableNode.interfaceState; + } else { + // Until we can always create an associated ASTableNode without a retain cycle, + // we might be on our own to try to guess if we're visible. The node normally + // handles this even if it is the root / directly added to the view hierarchy. + return (self.window != nil ? ASInterfaceStateVisible : ASInterfaceStateNone); + } } #pragma mark - ASRangeControllerDelegate From a02a60fa75120806827939178f1e06e9ea075d51 Mon Sep 17 00:00:00 2001 From: Christoph Zelazowski Date: Tue, 19 Jan 2016 19:55:22 -0800 Subject: [PATCH 10/27] Add error handler to ASNetworkImageNodeDelegate --- AsyncDisplayKit/ASNetworkImageNode.h | 10 ++++++++++ AsyncDisplayKit/ASNetworkImageNode.mm | 11 +++++++---- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/AsyncDisplayKit/ASNetworkImageNode.h b/AsyncDisplayKit/ASNetworkImageNode.h index 1d7134ca..82513a8c 100644 --- a/AsyncDisplayKit/ASNetworkImageNode.h +++ b/AsyncDisplayKit/ASNetworkImageNode.h @@ -95,6 +95,16 @@ NS_ASSUME_NONNULL_BEGIN @optional +/** + * Notification that the image node failed to download the image. + * + * @param imageNode The sender. + * @param error The error with details. + * + * @discussion Called on a background queue. + */ +- (void)imageNode:(ASNetworkImageNode *)imageNode didFailWithError:(NSError *)error; + /** * Notification that the image node finished decoding an image. * diff --git a/AsyncDisplayKit/ASNetworkImageNode.mm b/AsyncDisplayKit/ASNetworkImageNode.mm index cbba35af..5c5c8f37 100755 --- a/AsyncDisplayKit/ASNetworkImageNode.mm +++ b/AsyncDisplayKit/ASNetworkImageNode.mm @@ -168,14 +168,14 @@ _cacheUUID = nil; } -- (void)_downloadImageWithCompletion:(void (^)(CGImageRef))finished +- (void)_downloadImageWithCompletion:(void (^)(CGImageRef, NSError*))finished { _imageDownload = [_downloader downloadImageWithURL:_URL callbackQueue:dispatch_get_main_queue() downloadProgressBlock:NULL completion:^(CGImageRef responseImage, NSError *error) { if (finished != NULL) { - finished(responseImage); + finished(responseImage, error); } }]; } @@ -210,7 +210,7 @@ } } else { __weak __typeof__(self) weakSelf = self; - void (^finished)(CGImageRef) = ^(CGImageRef responseImage) { + void (^finished)(CGImageRef, NSError *) = ^(CGImageRef responseImage, NSError *error) { __typeof__(self) strongSelf = weakSelf; if (strongSelf == nil) { return; @@ -232,6 +232,9 @@ if (responseImage != NULL) { [strongSelf->_delegate imageNode:strongSelf didLoadImage:strongSelf.image]; } + else if (error && [strongSelf->_delegate respondsToSelector:@selector(imageNode:didFailWithError:)]) { + [strongSelf->_delegate imageNode:strongSelf didFailWithError:error]; + } }; if (_cache != nil) { @@ -247,7 +250,7 @@ if (image == NULL && _downloader != nil) { [self _downloadImageWithCompletion:finished]; } else { - finished(image); + finished(image, NULL); } }; From 42c56fc334781ddc539a2d8deea084838bf85afb Mon Sep 17 00:00:00 2001 From: aaronschubert0 Date: Wed, 20 Jan 2016 09:30:19 +0000 Subject: [PATCH 11/27] Update ReadMe to include Cocoapods badges As specified in #1086. Hey @appleguy Turns out these links have been there all along but were just hidden since they were using http (I think). The img.shields.io is a bit unstable at times but seems to be the best solution so far. Will update in future if better solutions come up! --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 4594f409..673bcd6b 100644 --- a/README.md +++ b/README.md @@ -2,9 +2,9 @@ [![Build Status](https://travis-ci.org/facebook/AsyncDisplayKit.svg)](https://travis-ci.org/facebook/AsyncDisplayKit) [![Coverage Status](https://coveralls.io/repos/facebook/AsyncDisplayKit/badge.svg?branch=master)](https://coveralls.io/r/facebook/AsyncDisplayKit?branch=master) - [![Version](http://img.shields.io/cocoapods/v/AsyncDisplayKit.svg)](http://cocoapods.org/?q=AsyncDisplayKit) - [![Platform](http://img.shields.io/cocoapods/p/AsyncDisplayKit.svg)]() - [![License](http://img.shields.io/cocoapods/l/AsyncDisplayKit.svg)](https://github.com/facebook/AsyncDisplayKit/blob/master/LICENSE) +[![Version](https://img.shields.io/cocoapods/v/AsyncDisplayKit.svg)](http://cocoapods.org/pods/AsyncDisplayKit) +[![Platform](https://img.shields.io/cocoapods/p/AsyncDisplayKit.svg)]() +[![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 631d04a45b2e02604dcff10de0257576651f24e4 Mon Sep 17 00:00:00 2001 From: Aaron Schubert Date: Wed, 20 Jan 2016 09:37:54 +0000 Subject: [PATCH 12/27] [ASTableView] Rename _ASTableViewCellDelegate method. --- AsyncDisplayKit/ASTableView.mm | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/AsyncDisplayKit/ASTableView.mm b/AsyncDisplayKit/ASTableView.mm index 85da55f0..416df918 100644 --- a/AsyncDisplayKit/ASTableView.mm +++ b/AsyncDisplayKit/ASTableView.mm @@ -34,7 +34,7 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell"; @class _ASTableViewCell; @protocol _ASTableViewCellDelegate -- (void)willLayoutSubviewsOfTableViewCell:(_ASTableViewCell *)tableViewCell; +- (void)didLayoutSubviewsOfTableViewCell:(_ASTableViewCell *)tableViewCell; @end @interface _ASTableViewCell : UITableViewCell @@ -48,7 +48,7 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell"; - (void)layoutSubviews { [super layoutSubviews]; - [_delegate willLayoutSubviewsOfTableViewCell:self]; + [_delegate didLayoutSubviewsOfTableViewCell:self]; } - (void)didTransitionToState:(UITableViewCellStateMask)state @@ -895,7 +895,7 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell"; #pragma mark - _ASTableViewCellDelegate -- (void)willLayoutSubviewsOfTableViewCell:(_ASTableViewCell *)tableViewCell +- (void)didLayoutSubviewsOfTableViewCell:(_ASTableViewCell *)tableViewCell { CGFloat contentViewWidth = tableViewCell.contentView.bounds.size.width; ASCellNode *node = tableViewCell.node; From da2cbf4644cb3c3502b5ab4f622a2151991c0b72 Mon Sep 17 00:00:00 2001 From: Bin Liu Date: Thu, 14 Jan 2016 15:46:20 -0800 Subject: [PATCH 13/27] initial design --- AsyncDisplayKit/ASCollectionView.h | 2 ++ AsyncDisplayKit/ASCollectionView.mm | 14 +++++++++++++ ...SCollectionViewLayoutFacilitatorProtocol.h | 20 +++++++++++++++++++ 3 files changed, 36 insertions(+) create mode 100644 AsyncDisplayKit/ASCollectionViewLayoutFacilitatorProtocol.h diff --git a/AsyncDisplayKit/ASCollectionView.h b/AsyncDisplayKit/ASCollectionView.h index 774a44a7..f9352567 100644 --- a/AsyncDisplayKit/ASCollectionView.h +++ b/AsyncDisplayKit/ASCollectionView.h @@ -13,6 +13,7 @@ #import #import #import +#import @class ASCellNode; @class ASCollectionNode; @@ -43,6 +44,7 @@ NS_ASSUME_NONNULL_BEGIN */ - (instancetype)initWithCollectionViewLayout:(UICollectionViewLayout *)layout; - (instancetype)initWithFrame:(CGRect)frame collectionViewLayout:(UICollectionViewLayout *)layout; +- (instancetype)initWithFrame:(CGRect)frame collectionViewLayout:(UICollectionViewLayout *)layout layoutFacilitator:(id)layoutFacilitator; // The corresponding ASCollectionNode, which exists even if directly allocating & handling the view class. @property (nonatomic, weak, readonly) ASCollectionNode *collectionNode; diff --git a/AsyncDisplayKit/ASCollectionView.mm b/AsyncDisplayKit/ASCollectionView.mm index 5e8b7c03..fd973ca3 100644 --- a/AsyncDisplayKit/ASCollectionView.mm +++ b/AsyncDisplayKit/ASCollectionView.mm @@ -20,6 +20,8 @@ #import "UICollectionViewLayout+ASConvenience.h" #import "_ASDisplayLayer.h" +#import "ASCollectionViewLayoutFacilitatorProtocol.h" + static const NSUInteger kASCollectionViewAnimationNone = UITableViewRowAnimationNone; static const ASSizeRange kInvalidSizeRange = {CGSizeZero, CGSizeZero}; static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell"; @@ -67,6 +69,8 @@ static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell"; ASRangeController *_rangeController; ASCollectionViewLayoutController *_layoutController; ASCollectionViewFlowLayoutInspector *_flowLayoutInspector; + + id _layoutFacilitator; BOOL _performingBatchUpdates; NSMutableArray *_batchUpdateBlocks; @@ -137,6 +141,13 @@ static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell"; return [self _initWithFrame:frame collectionViewLayout:layout ownedByNode:NO]; } +- (instancetype)initWithFrame:(CGRect)frame collectionViewLayout:(UICollectionViewLayout *)layout layoutFacilitator:(id)layoutFacilitator +{ + self = [self _initWithFrame:frame collectionViewLayout:layout ownedByNode:NO]; + _layoutFacilitator = layoutFacilitator; + return self; +} + // FIXME: This method is deprecated and will probably be removed in or shortly after 2.0. - (instancetype)initWithFrame:(CGRect)frame collectionViewLayout:(UICollectionViewLayout *)layout asyncDataFetching:(BOOL)asyncDataFetchingEnabled { @@ -412,12 +423,14 @@ static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell"; - (void)insertSections:(NSIndexSet *)sections { ASDisplayNodeAssertMainThread(); + [_layoutFacilitator collectionViewInsertingSectionsAtIndexSet:sections]; [_dataController insertSections:sections withAnimationOptions:kASCollectionViewAnimationNone]; } - (void)deleteSections:(NSIndexSet *)sections { ASDisplayNodeAssertMainThread(); + [_layoutFacilitator collectionViewDeletingSectionsAtIndexSet:sections]; [_dataController deleteSections:sections withAnimationOptions:kASCollectionViewAnimationNone]; } @@ -436,6 +449,7 @@ static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell"; - (void)insertItemsAtIndexPaths:(NSArray *)indexPaths { ASDisplayNodeAssertMainThread(); + [_layoutFacilitator collectionViewInsertingCellAtIndexPaths:indexPaths]; [_dataController insertRowsAtIndexPaths:indexPaths withAnimationOptions:kASCollectionViewAnimationNone]; } diff --git a/AsyncDisplayKit/ASCollectionViewLayoutFacilitatorProtocol.h b/AsyncDisplayKit/ASCollectionViewLayoutFacilitatorProtocol.h new file mode 100644 index 00000000..323b6403 --- /dev/null +++ b/AsyncDisplayKit/ASCollectionViewLayoutFacilitatorProtocol.h @@ -0,0 +1,20 @@ +// +// ASCollectionViewLayoutFacilitatorProtocol.h +// Pods +// +// Created by Bin Liu on 1/13/16. +// +// + +#ifndef ASCollectionViewLayoutFacilitatorProtocol_h +#define ASCollectionViewLayoutFacilitatorProtocol_h + +@protocol ASCollectionViewLayoutFacilitatorProtocol + +- (void)collectionViewInsertingCellAtIndexPaths:(NSArray *)indexPaths; +- (void)collectionViewInsertingSectionsAtIndexSet:(NSIndexSet *)indexes; +- (void)collectionViewDeletingSectionsAtIndexSet:(NSIndexSet *)indexes; + +@end + +#endif /* ASCollectionViewLayoutFacilitatorProtocol_h */ From bc92c64e8c1b2f0dc1c82686642955f24d0d0f2a Mon Sep 17 00:00:00 2001 From: Bin Liu Date: Wed, 20 Jan 2016 02:34:12 -0800 Subject: [PATCH 14/27] Proposed version 1 --- AsyncDisplayKit/ASCollectionView.mm | 13 +++++-------- .../ASCollectionViewLayoutFacilitatorProtocol.h | 5 ++--- 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/AsyncDisplayKit/ASCollectionView.mm b/AsyncDisplayKit/ASCollectionView.mm index fd973ca3..a28ab5ab 100644 --- a/AsyncDisplayKit/ASCollectionView.mm +++ b/AsyncDisplayKit/ASCollectionView.mm @@ -423,14 +423,12 @@ static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell"; - (void)insertSections:(NSIndexSet *)sections { ASDisplayNodeAssertMainThread(); - [_layoutFacilitator collectionViewInsertingSectionsAtIndexSet:sections]; [_dataController insertSections:sections withAnimationOptions:kASCollectionViewAnimationNone]; } - (void)deleteSections:(NSIndexSet *)sections { ASDisplayNodeAssertMainThread(); - [_layoutFacilitator collectionViewDeletingSectionsAtIndexSet:sections]; [_dataController deleteSections:sections withAnimationOptions:kASCollectionViewAnimationNone]; } @@ -449,7 +447,6 @@ static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell"; - (void)insertItemsAtIndexPaths:(NSArray *)indexPaths { ASDisplayNodeAssertMainThread(); - [_layoutFacilitator collectionViewInsertingCellAtIndexPaths:indexPaths]; [_dataController insertRowsAtIndexPaths:indexPaths withAnimationOptions:kASCollectionViewAnimationNone]; } @@ -847,7 +844,7 @@ static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell"; - (void)rangeController:(ASRangeController *)rangeController didEndUpdatesAnimated:(BOOL)animated completion:(void (^)(BOOL))completion { ASDisplayNodeAssertMainThread(); - + if (!self.asyncDataSource || _superIsPendingDataLoad) { if (completion) { completion(NO); @@ -870,7 +867,7 @@ static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell"; - (void)rangeController:(ASRangeController *)rangeController didInsertNodes:(NSArray *)nodes atIndexPaths:(NSArray *)indexPaths withAnimationOptions:(ASDataControllerAnimationOptions)animationOptions { ASDisplayNodeAssertMainThread(); - + [_layoutFacilitator collectionViewEditingCellsAtIndexPaths:indexPaths]; if (!self.asyncDataSource || _superIsPendingDataLoad) { return; // if the asyncDataSource has become invalid while we are processing, ignore this request to avoid crashes } @@ -889,7 +886,7 @@ static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell"; - (void)rangeController:(ASRangeController *)rangeController didDeleteNodes:(NSArray *)nodes atIndexPaths:(NSArray *)indexPaths withAnimationOptions:(ASDataControllerAnimationOptions)animationOptions { ASDisplayNodeAssertMainThread(); - + [_layoutFacilitator collectionViewEditingCellsAtIndexPaths:indexPaths]; if (!self.asyncDataSource || _superIsPendingDataLoad) { return; // if the asyncDataSource has become invalid while we are processing, ignore this request to avoid crashes } @@ -908,7 +905,7 @@ static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell"; - (void)rangeController:(ASRangeController *)rangeController didInsertSectionsAtIndexSet:(NSIndexSet *)indexSet withAnimationOptions:(ASDataControllerAnimationOptions)animationOptions { ASDisplayNodeAssertMainThread(); - + [_layoutFacilitator collectionViewEditingSectionsAtIndexSet:indexSet]; if (!self.asyncDataSource || _superIsPendingDataLoad) { return; // if the asyncDataSource has become invalid while we are processing, ignore this request to avoid crashes } @@ -927,7 +924,7 @@ static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell"; - (void)rangeController:(ASRangeController *)rangeController didDeleteSectionsAtIndexSet:(NSIndexSet *)indexSet withAnimationOptions:(ASDataControllerAnimationOptions)animationOptions { ASDisplayNodeAssertMainThread(); - + [_layoutFacilitator collectionViewEditingSectionsAtIndexSet:indexSet]; if (!self.asyncDataSource || _superIsPendingDataLoad) { return; // if the asyncDataSource has become invalid while we are processing, ignore this request to avoid crashes } diff --git a/AsyncDisplayKit/ASCollectionViewLayoutFacilitatorProtocol.h b/AsyncDisplayKit/ASCollectionViewLayoutFacilitatorProtocol.h index 323b6403..d3fa1d41 100644 --- a/AsyncDisplayKit/ASCollectionViewLayoutFacilitatorProtocol.h +++ b/AsyncDisplayKit/ASCollectionViewLayoutFacilitatorProtocol.h @@ -11,9 +11,8 @@ @protocol ASCollectionViewLayoutFacilitatorProtocol -- (void)collectionViewInsertingCellAtIndexPaths:(NSArray *)indexPaths; -- (void)collectionViewInsertingSectionsAtIndexSet:(NSIndexSet *)indexes; -- (void)collectionViewDeletingSectionsAtIndexSet:(NSIndexSet *)indexes; +- (void)collectionViewEditingCellsAtIndexPaths:(NSArray *)indexPaths; +- (void)collectionViewEditingSectionsAtIndexSet:(NSIndexSet *)indexes; @end From db18724d5b5e451cb5908ebd151d73a49314166c Mon Sep 17 00:00:00 2001 From: Adlai Holler Date: Wed, 20 Jan 2016 14:00:46 -0800 Subject: [PATCH 15/27] If they set attributedString to nil twice, ignore the second one. --- AsyncDisplayKit/ASTextNode.mm | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/AsyncDisplayKit/ASTextNode.mm b/AsyncDisplayKit/ASTextNode.mm index 9ad5437b..7eac0593 100644 --- a/AsyncDisplayKit/ASTextNode.mm +++ b/AsyncDisplayKit/ASTextNode.mm @@ -336,14 +336,14 @@ static NSArray *DefaultLinkAttributeNames = @[ NSLinkAttributeName ]; - (void)setAttributedString:(NSAttributedString *)attributedString { - if (ASObjectIsEqual(attributedString, _attributedString)) { - return; - } - if (attributedString == nil) { attributedString = [[NSAttributedString alloc] initWithString:@"" attributes:nil]; } + if (ASObjectIsEqual(attributedString, _attributedString)) { + return; + } + _attributedString = ASCleanseAttributedStringOfCoreTextAttributes(attributedString); // Sync the truncation string with attributes from the updated _attributedString From 882379a820e167f75eed218f6cfc3add3a9f1f3b Mon Sep 17 00:00:00 2001 From: Luke Zhao Date: Tue, 19 Jan 2016 19:50:20 -0800 Subject: [PATCH 16/27] Update comments for ASPanningOverriddenUITextView --- AsyncDisplayKit/ASEditableTextNode.h | 1 + AsyncDisplayKit/ASEditableTextNode.mm | 15 +++++++++++++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/AsyncDisplayKit/ASEditableTextNode.h b/AsyncDisplayKit/ASEditableTextNode.h index af2c17dd..832611c0 100644 --- a/AsyncDisplayKit/ASEditableTextNode.h +++ b/AsyncDisplayKit/ASEditableTextNode.h @@ -25,6 +25,7 @@ NS_ASSUME_NONNULL_BEGIN /** @abstract Enable scrolling on the textView + @default true */ @property (nonatomic) BOOL scrollEnabled; diff --git a/AsyncDisplayKit/ASEditableTextNode.mm b/AsyncDisplayKit/ASEditableTextNode.mm index d27695a4..06accae2 100644 --- a/AsyncDisplayKit/ASEditableTextNode.mm +++ b/AsyncDisplayKit/ASEditableTextNode.mm @@ -16,8 +16,19 @@ #import "ASTextNodeWordKerner.h" #import "ASThread.h" -//! @abstract This subclass forces the parent UITextView's scrollEnabled property to always be true. Instead, it disables the panGestureRecognizer when scrollEnabled is set to false. This ensures that the contentSize is caculated correctly. -//! See issue: https://github.com/facebook/AsyncDisplayKit/issues/1063 +/** + @abstract As originally reported in rdar://14729288, when scrollEnabled = NO, + UITextView does not calculate its contentSize. This makes it difficult + for a client to embed a UITextView inside a different scroll view with + other content (setting scrollEnabled = NO on the UITextView itself, + because the containing scroll view will handle the gesture)... + because accessing contentSize is typically necessary to perform layout. + Apple later closed the issue as expected behavior. This works around + the issue by ensuring that contentSize is always calculated, while + still providing control over the UITextView's scrolling. + + See issue: https://github.com/facebook/AsyncDisplayKit/issues/1063 + */ @interface ASPanningOverriddenUITextView : UITextView { BOOL _shouldBlockPanGesture; From 2fc474ee75db8f60c11db13f45eac822d1a4492a Mon Sep 17 00:00:00 2001 From: aaronschubert0 Date: Thu, 21 Jan 2016 09:54:36 +0000 Subject: [PATCH 17/27] Include manual downloads badge --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 673bcd6b..68c98c51 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,7 @@ [![Version](https://img.shields.io/cocoapods/v/AsyncDisplayKit.svg)](http://cocoapods.org/pods/AsyncDisplayKit) [![Platform](https://img.shields.io/cocoapods/p/AsyncDisplayKit.svg)]() [![License](https://img.shields.io/cocoapods/l/AsyncDisplayKit.svg)](https://github.com/facebook/AsyncDisplayKit/blob/master/LICENSE) +[![Downloads](https://img.shields.io/badge/downloads-%3E120k-green.svg)](http://cocoapods.org/pods/AsyncDisplayKit) 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 d07759ca40ce160a9ddeb602732490b689620db3 Mon Sep 17 00:00:00 2001 From: Bin Liu Date: Thu, 21 Jan 2016 09:57:28 -0800 Subject: [PATCH 18/27] Add file to project --- AsyncDisplayKit.xcodeproj/project.pbxproj | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/AsyncDisplayKit.xcodeproj/project.pbxproj b/AsyncDisplayKit.xcodeproj/project.pbxproj index 8437e368..460633e5 100644 --- a/AsyncDisplayKit.xcodeproj/project.pbxproj +++ b/AsyncDisplayKit.xcodeproj/project.pbxproj @@ -357,6 +357,7 @@ ACF6ED631B178DC700DA7C62 /* ASStackLayoutSpecSnapshotTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = ACF6ED5B1B178DC700DA7C62 /* ASStackLayoutSpecSnapshotTests.mm */; }; B0F8805A1BEAEC7500D17647 /* ASTableNode.h in Headers */ = {isa = PBXBuildFile; fileRef = B0F880581BEAEC7500D17647 /* ASTableNode.h */; settings = {ATTRIBUTES = (Public, ); }; }; B0F8805B1BEAEC7500D17647 /* ASTableNode.m in Sources */ = {isa = PBXBuildFile; fileRef = B0F880591BEAEC7500D17647 /* ASTableNode.m */; }; + B13CA0F01C51536E00E031AB /* ASCollectionViewLayoutFacilitatorProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = B13CA0EF1C51536E00E031AB /* ASCollectionViewLayoutFacilitatorProtocol.h */; }; B35061F31B010EFD0018CF92 /* ASCellNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 055F1A3A19ABD43F004DAFF1 /* ASCellNode.h */; settings = {ATTRIBUTES = (Public, ); }; }; B35061F51B010EFD0018CF92 /* ASCollectionView.h in Headers */ = {isa = PBXBuildFile; fileRef = AC3C4A4F1A1139C100143C57 /* ASCollectionView.h */; settings = {ATTRIBUTES = (Public, ); }; }; B35061F61B010EFD0018CF92 /* ASCollectionView.mm in Sources */ = {isa = PBXBuildFile; fileRef = AC3C4A501A1139C100143C57 /* ASCollectionView.mm */; }; @@ -765,6 +766,7 @@ ACF6ED5B1B178DC700DA7C62 /* ASStackLayoutSpecSnapshotTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASStackLayoutSpecSnapshotTests.mm; sourceTree = ""; }; B0F880581BEAEC7500D17647 /* ASTableNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASTableNode.h; sourceTree = ""; }; B0F880591BEAEC7500D17647 /* ASTableNode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASTableNode.m; sourceTree = ""; }; + B13CA0EF1C51536E00E031AB /* ASCollectionViewLayoutFacilitatorProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASCollectionViewLayoutFacilitatorProtocol.h; sourceTree = ""; }; B35061DA1B010EDF0018CF92 /* AsyncDisplayKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = AsyncDisplayKit.framework; sourceTree = BUILT_PRODUCTS_DIR; }; B35061DD1B010EDF0018CF92 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = "../AsyncDisplayKit-iOS/Info.plist"; sourceTree = ""; }; CC7FD9DC1BB5E962005CCB2B /* ASPhotosFrameworkImageRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASPhotosFrameworkImageRequest.h; sourceTree = ""; }; @@ -908,6 +910,7 @@ AC3C4A4F1A1139C100143C57 /* ASCollectionView.h */, AC3C4A501A1139C100143C57 /* ASCollectionView.mm */, AC3C4A531A113EEC00143C57 /* ASCollectionViewProtocols.h */, + B13CA0EF1C51536E00E031AB /* ASCollectionViewLayoutFacilitatorProtocol.h */, DEC146B41C37A16A004A0EE7 /* ASCollectionInternal.h */, DEC146B51C37A16A004A0EE7 /* ASCollectionInternal.m */, 058D09D5195D050800B7D73C /* ASControlNode.h */, @@ -1276,6 +1279,7 @@ 058D0A72195D05F800B7D73C /* _ASCoreAnimationExtras.h in Headers */, 058D0A53195D05DC00B7D73C /* _ASDisplayLayer.h in Headers */, 058D0A55195D05DC00B7D73C /* _ASDisplayView.h in Headers */, + B13CA0F01C51536E00E031AB /* ASCollectionViewLayoutFacilitatorProtocol.h in Headers */, 058D0A74195D05F800B7D73C /* _ASPendingState.h in Headers */, 9C5586691BD549CB00B50E3A /* ASAsciiArtBoxCreator.h in Headers */, 058D0A76195D05F900B7D73C /* _ASScopeTimer.h in Headers */, From 726bc7d668eec2a75cf6e6577a162a009438f13e Mon Sep 17 00:00:00 2001 From: Bin Liu Date: Thu, 21 Jan 2016 11:14:00 -0800 Subject: [PATCH 19/27] addressed comments --- AsyncDisplayKit.xcodeproj/project.pbxproj | 8 ++--- AsyncDisplayKit/ASCollectionNode.h | 1 + AsyncDisplayKit/ASCollectionNode.mm | 7 ++++- AsyncDisplayKit/ASCollectionView.mm | 8 +++-- ...SCollectionViewLayoutFacilitatorProtocol.h | 19 ------------ .../Details/ASCollectionInternal.h | 2 +- ...SCollectionViewLayoutFacilitatorProtocol.h | 30 +++++++++++++++++++ 7 files changed, 48 insertions(+), 27 deletions(-) delete mode 100644 AsyncDisplayKit/ASCollectionViewLayoutFacilitatorProtocol.h create mode 100644 AsyncDisplayKit/Details/ASCollectionViewLayoutFacilitatorProtocol.h diff --git a/AsyncDisplayKit.xcodeproj/project.pbxproj b/AsyncDisplayKit.xcodeproj/project.pbxproj index 460633e5..bbdacf50 100644 --- a/AsyncDisplayKit.xcodeproj/project.pbxproj +++ b/AsyncDisplayKit.xcodeproj/project.pbxproj @@ -357,7 +357,7 @@ ACF6ED631B178DC700DA7C62 /* ASStackLayoutSpecSnapshotTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = ACF6ED5B1B178DC700DA7C62 /* ASStackLayoutSpecSnapshotTests.mm */; }; B0F8805A1BEAEC7500D17647 /* ASTableNode.h in Headers */ = {isa = PBXBuildFile; fileRef = B0F880581BEAEC7500D17647 /* ASTableNode.h */; settings = {ATTRIBUTES = (Public, ); }; }; B0F8805B1BEAEC7500D17647 /* ASTableNode.m in Sources */ = {isa = PBXBuildFile; fileRef = B0F880591BEAEC7500D17647 /* ASTableNode.m */; }; - B13CA0F01C51536E00E031AB /* ASCollectionViewLayoutFacilitatorProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = B13CA0EF1C51536E00E031AB /* ASCollectionViewLayoutFacilitatorProtocol.h */; }; + B13CA0F21C51653000E031AB /* ASCollectionViewLayoutFacilitatorProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = B13CA0F11C51653000E031AB /* ASCollectionViewLayoutFacilitatorProtocol.h */; }; B35061F31B010EFD0018CF92 /* ASCellNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 055F1A3A19ABD43F004DAFF1 /* ASCellNode.h */; settings = {ATTRIBUTES = (Public, ); }; }; B35061F51B010EFD0018CF92 /* ASCollectionView.h in Headers */ = {isa = PBXBuildFile; fileRef = AC3C4A4F1A1139C100143C57 /* ASCollectionView.h */; settings = {ATTRIBUTES = (Public, ); }; }; B35061F61B010EFD0018CF92 /* ASCollectionView.mm in Sources */ = {isa = PBXBuildFile; fileRef = AC3C4A501A1139C100143C57 /* ASCollectionView.mm */; }; @@ -766,7 +766,7 @@ ACF6ED5B1B178DC700DA7C62 /* ASStackLayoutSpecSnapshotTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASStackLayoutSpecSnapshotTests.mm; sourceTree = ""; }; B0F880581BEAEC7500D17647 /* ASTableNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASTableNode.h; sourceTree = ""; }; B0F880591BEAEC7500D17647 /* ASTableNode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASTableNode.m; sourceTree = ""; }; - B13CA0EF1C51536E00E031AB /* ASCollectionViewLayoutFacilitatorProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASCollectionViewLayoutFacilitatorProtocol.h; sourceTree = ""; }; + B13CA0F11C51653000E031AB /* ASCollectionViewLayoutFacilitatorProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASCollectionViewLayoutFacilitatorProtocol.h; sourceTree = ""; }; B35061DA1B010EDF0018CF92 /* AsyncDisplayKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = AsyncDisplayKit.framework; sourceTree = BUILT_PRODUCTS_DIR; }; B35061DD1B010EDF0018CF92 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = "../AsyncDisplayKit-iOS/Info.plist"; sourceTree = ""; }; CC7FD9DC1BB5E962005CCB2B /* ASPhotosFrameworkImageRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASPhotosFrameworkImageRequest.h; sourceTree = ""; }; @@ -910,7 +910,6 @@ AC3C4A4F1A1139C100143C57 /* ASCollectionView.h */, AC3C4A501A1139C100143C57 /* ASCollectionView.mm */, AC3C4A531A113EEC00143C57 /* ASCollectionViewProtocols.h */, - B13CA0EF1C51536E00E031AB /* ASCollectionViewLayoutFacilitatorProtocol.h */, DEC146B41C37A16A004A0EE7 /* ASCollectionInternal.h */, DEC146B51C37A16A004A0EE7 /* ASCollectionInternal.m */, 058D09D5195D050800B7D73C /* ASControlNode.h */, @@ -1038,6 +1037,7 @@ 299DA1A81A828D2900162D41 /* ASBatchContext.mm */, 205F0E1B1B373A2C007741D0 /* ASCollectionViewLayoutController.h */, 205F0E1C1B373A2C007741D0 /* ASCollectionViewLayoutController.mm */, + B13CA0F11C51653000E031AB /* ASCollectionViewLayoutFacilitatorProtocol.h */, 05A6D05819D0EB64002DD95E /* ASDealloc2MainObject.h */, 05A6D05919D0EB64002DD95E /* ASDealloc2MainObject.m */, 4640521B1A3F83C40061C0BA /* ASFlowLayoutController.h */, @@ -1279,7 +1279,7 @@ 058D0A72195D05F800B7D73C /* _ASCoreAnimationExtras.h in Headers */, 058D0A53195D05DC00B7D73C /* _ASDisplayLayer.h in Headers */, 058D0A55195D05DC00B7D73C /* _ASDisplayView.h in Headers */, - B13CA0F01C51536E00E031AB /* ASCollectionViewLayoutFacilitatorProtocol.h in Headers */, + B13CA0F21C51653000E031AB /* ASCollectionViewLayoutFacilitatorProtocol.h in Headers */, 058D0A74195D05F800B7D73C /* _ASPendingState.h in Headers */, 9C5586691BD549CB00B50E3A /* ASAsciiArtBoxCreator.h in Headers */, 058D0A76195D05F900B7D73C /* _ASScopeTimer.h in Headers */, diff --git a/AsyncDisplayKit/ASCollectionNode.h b/AsyncDisplayKit/ASCollectionNode.h index 7f9b6e31..1c236aaf 100644 --- a/AsyncDisplayKit/ASCollectionNode.h +++ b/AsyncDisplayKit/ASCollectionNode.h @@ -18,6 +18,7 @@ NS_ASSUME_NONNULL_BEGIN - (instancetype)initWithCollectionViewLayout:(UICollectionViewLayout *)layout; - (instancetype)initWithFrame:(CGRect)frame collectionViewLayout:(UICollectionViewLayout *)layout; +- (instancetype)initWithFrame:(CGRect)frame collectionViewLayout:(UICollectionViewLayout *)layout layoutFacilitator:(id)layoutFacilitator; @property (weak, nonatomic) id delegate; @property (weak, nonatomic) id dataSource; diff --git a/AsyncDisplayKit/ASCollectionNode.mm b/AsyncDisplayKit/ASCollectionNode.mm index f184a969..a8f2055f 100644 --- a/AsyncDisplayKit/ASCollectionNode.mm +++ b/AsyncDisplayKit/ASCollectionNode.mm @@ -83,9 +83,14 @@ } - (instancetype)initWithFrame:(CGRect)frame collectionViewLayout:(UICollectionViewLayout *)layout +{ + return [self initWithFrame:frame collectionViewLayout:layout layoutFacilitator:nil]; +} + +- (instancetype)initWithFrame:(CGRect)frame collectionViewLayout:(UICollectionViewLayout *)layout layoutFacilitator:(id)layoutFacilitator { ASDisplayNodeViewBlock collectionViewBlock = ^UIView *{ - return [[ASCollectionView alloc] _initWithFrame:frame collectionViewLayout:layout ownedByNode:YES]; + return [[ASCollectionView alloc] _initWithFrame:CGRectZero collectionViewLayout:layout layoutFacilitator:layoutFacilitator ownedByNode:YES]; }; if (self = [super initWithViewBlock:collectionViewBlock]) { diff --git a/AsyncDisplayKit/ASCollectionView.mm b/AsyncDisplayKit/ASCollectionView.mm index a28ab5ab..83065aa3 100644 --- a/AsyncDisplayKit/ASCollectionView.mm +++ b/AsyncDisplayKit/ASCollectionView.mm @@ -20,8 +20,6 @@ #import "UICollectionViewLayout+ASConvenience.h" #import "_ASDisplayLayer.h" -#import "ASCollectionViewLayoutFacilitatorProtocol.h" - static const NSUInteger kASCollectionViewAnimationNone = UITableViewRowAnimationNone; static const ASSizeRange kInvalidSizeRange = {CGSizeZero, CGSizeZero}; static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell"; @@ -155,6 +153,11 @@ static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell"; } - (instancetype)_initWithFrame:(CGRect)frame collectionViewLayout:(UICollectionViewLayout *)layout ownedByNode:(BOOL)ownedByNode +{ + return [self _initWithFrame:frame collectionViewLayout:layout layoutFacilitator:nil ownedByNode:ownedByNode]; +} + +- (instancetype)_initWithFrame:(CGRect)frame collectionViewLayout:(UICollectionViewLayout *)layout layoutFacilitator:(id)layoutFacilitator ownedByNode:(BOOL)ownedByNode { if (!(self = [super initWithFrame:frame collectionViewLayout:layout])) return nil; @@ -206,6 +209,7 @@ static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell"; if ([layout asdk_isFlowLayout]) { _layoutInspector = [self flowLayoutInspector]; } + _layoutFacilitator = layoutFacilitator; _proxyDelegate = [[ASCollectionViewProxy alloc] initWithTarget:nil interceptor:self]; super.delegate = (id)_proxyDelegate; diff --git a/AsyncDisplayKit/ASCollectionViewLayoutFacilitatorProtocol.h b/AsyncDisplayKit/ASCollectionViewLayoutFacilitatorProtocol.h deleted file mode 100644 index d3fa1d41..00000000 --- a/AsyncDisplayKit/ASCollectionViewLayoutFacilitatorProtocol.h +++ /dev/null @@ -1,19 +0,0 @@ -// -// ASCollectionViewLayoutFacilitatorProtocol.h -// Pods -// -// Created by Bin Liu on 1/13/16. -// -// - -#ifndef ASCollectionViewLayoutFacilitatorProtocol_h -#define ASCollectionViewLayoutFacilitatorProtocol_h - -@protocol ASCollectionViewLayoutFacilitatorProtocol - -- (void)collectionViewEditingCellsAtIndexPaths:(NSArray *)indexPaths; -- (void)collectionViewEditingSectionsAtIndexSet:(NSIndexSet *)indexes; - -@end - -#endif /* ASCollectionViewLayoutFacilitatorProtocol_h */ diff --git a/AsyncDisplayKit/Details/ASCollectionInternal.h b/AsyncDisplayKit/Details/ASCollectionInternal.h index 9b72548f..a0aff1e5 100644 --- a/AsyncDisplayKit/Details/ASCollectionInternal.h +++ b/AsyncDisplayKit/Details/ASCollectionInternal.h @@ -11,7 +11,7 @@ #import "ASRangeController.h" @interface ASCollectionView () -- (instancetype)_initWithFrame:(CGRect)frame collectionViewLayout:(UICollectionViewLayout *)layout ownedByNode:(BOOL)ownedByNode; +- (instancetype)_initWithFrame:(CGRect)frame collectionViewLayout:(UICollectionViewLayout *)layout layoutFacilitator:(id)layoutFacilitator ownedByNode:(BOOL)ownedByNode; @property (nonatomic, weak, readwrite) ASCollectionNode *collectionNode; @property (nonatomic, strong, readonly) ASRangeController *rangeController; diff --git a/AsyncDisplayKit/Details/ASCollectionViewLayoutFacilitatorProtocol.h b/AsyncDisplayKit/Details/ASCollectionViewLayoutFacilitatorProtocol.h new file mode 100644 index 00000000..719c9841 --- /dev/null +++ b/AsyncDisplayKit/Details/ASCollectionViewLayoutFacilitatorProtocol.h @@ -0,0 +1,30 @@ +/* Copyright (c) 2014-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +#ifndef ASCollectionViewLayoutFacilitatorProtocol_h +#define ASCollectionViewLayoutFacilitatorProtocol_h + +/** + * This facilitator protocol is intended to help Layout to better + * gel with the CollectionView + */ +@protocol ASCollectionViewLayoutFacilitatorProtocol + +/** + * Inform that the collectionView is editing the cells at a list of indexPaths + */ +- (void)collectionViewEditingCellsAtIndexPaths:(NSArray *)indexPaths; + +/** + * Inform that the collectionView is editing the sections at a set of indexes + */ +- (void)collectionViewEditingSectionsAtIndexSet:(NSIndexSet *)indexes; + +@end + +#endif /* ASCollectionViewLayoutFacilitatorProtocol_h */ From 2e4d716e0b65465d9c65b5821668c38e5fa956c9 Mon Sep 17 00:00:00 2001 From: Huy Nguyen Date: Wed, 20 Jan 2016 17:50:01 -0800 Subject: [PATCH 20/27] ASDataController now handles reloadData more efficiently and notify its delegate once instead of a series of deletes and inserts --- AsyncDisplayKit/ASCollectionView.mm | 23 ++- AsyncDisplayKit/ASTableView.mm | 20 ++- .../Details/ASCollectionDataController.mm | 2 +- AsyncDisplayKit/Details/ASDataController.h | 9 +- AsyncDisplayKit/Details/ASDataController.mm | 133 ++++++++++++++---- AsyncDisplayKit/Details/ASRangeController.h | 7 + AsyncDisplayKit/Details/ASRangeController.mm | 13 ++ .../Details/ASRangeControllerBeta.mm | 8 ++ 8 files changed, 179 insertions(+), 36 deletions(-) diff --git a/AsyncDisplayKit/ASCollectionView.mm b/AsyncDisplayKit/ASCollectionView.mm index 5e8b7c03..1b99dbb3 100644 --- a/AsyncDisplayKit/ASCollectionView.mm +++ b/AsyncDisplayKit/ASCollectionView.mm @@ -241,7 +241,7 @@ static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell"; _superIsPendingDataLoad = YES; [super reloadData]; }); - [_dataController reloadDataWithAnimationOptions:kASCollectionViewAnimationNone completion:completion]; + [_dataController reloadDataWithCompletion:completion]; } - (void)reloadData @@ -253,7 +253,7 @@ static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell"; { ASDisplayNodeAssertMainThread(); _superIsPendingDataLoad = YES; - [_dataController reloadDataImmediatelyWithAnimationOptions:kASCollectionViewAnimationNone]; + [_dataController reloadDataImmediately]; [super reloadData]; } @@ -929,6 +929,25 @@ static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell"; } } +- (void)rangeControllerDidReloadData:(ASRangeController *)rangeController +{ + ASDisplayNodeAssertMainThread(); + + if (!self.asyncDataSource || _superIsPendingDataLoad) { + return; // if the asyncDataSource has become invalid while we are processing, ignore this request to avoid crashes + } + + if (_performingBatchUpdates) { + [_batchUpdateBlocks addObject:^{ + [super reloadData]; + }]; + } else { + [UIView performWithoutAnimation:^{ + [super reloadData]; + }]; + } +} + #pragma mark - ASCellNodeDelegate - (void)nodeDidRelayout:(ASCellNode *)node sizeChanged:(BOOL)sizeChanged diff --git a/AsyncDisplayKit/ASTableView.mm b/AsyncDisplayKit/ASTableView.mm index 88a54cc3..de9bb488 100644 --- a/AsyncDisplayKit/ASTableView.mm +++ b/AsyncDisplayKit/ASTableView.mm @@ -298,10 +298,7 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell"; - (void)reloadDataWithCompletion:(void (^)())completion { - ASPerformBlockOnMainThread(^{ - [super reloadData]; - }); - [_dataController reloadDataWithAnimationOptions:UITableViewRowAnimationNone completion:completion]; + [_dataController reloadDataWithCompletion:completion]; } - (void)reloadData @@ -312,8 +309,7 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell"; - (void)reloadDataImmediately { ASDisplayNodeAssertMainThread(); - [_dataController reloadDataImmediatelyWithAnimationOptions:UITableViewRowAnimationNone]; - [super reloadData]; + [_dataController reloadDataImmediately]; } - (void)setTuningParameters:(ASRangeTuningParameters)tuningParameters forRangeType:(ASLayoutRangeType)rangeType @@ -845,6 +841,18 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell"; }); } +- (void)rangeControllerDidReloadData:(ASRangeController *)rangeController +{ + ASDisplayNodeAssertMainThread(); + LOG(@"UITableView reloadData"); + + if (!self.asyncDataSource) { + return; // if the asyncDataSource has become invalid while we are processing, ignore this request to avoid crashes + } + + [super reloadData]; +} + #pragma mark - ASDataControllerDelegate - (ASCellNode *)dataController:(ASDataController *)dataController nodeAtIndexPath:(NSIndexPath *)indexPath diff --git a/AsyncDisplayKit/Details/ASCollectionDataController.mm b/AsyncDisplayKit/Details/ASCollectionDataController.mm index 9e51ee6a..5b433104 100644 --- a/AsyncDisplayKit/Details/ASCollectionDataController.mm +++ b/AsyncDisplayKit/Details/ASCollectionDataController.mm @@ -55,7 +55,7 @@ - (void)willReloadData { - [_pendingNodes enumerateKeysAndObjectsUsingBlock:^(NSString *kind, NSMutableArray *nodes, BOOL *stop) { + [_pendingNodes enumerateKeysAndObjectsUsingBlock:^(NSString *kind, NSMutableArray *nodes, BOOL *stop) { // Remove everything that existed before the reload, now that we're ready to insert replacements NSArray *indexPaths = [self indexPathsForEditingNodesOfKind:kind]; [self deleteNodesOfKind:kind atIndexPaths:indexPaths completion:nil]; diff --git a/AsyncDisplayKit/Details/ASDataController.h b/AsyncDisplayKit/Details/ASDataController.h index 5710b22b..113c5826 100644 --- a/AsyncDisplayKit/Details/ASDataController.h +++ b/AsyncDisplayKit/Details/ASDataController.h @@ -94,6 +94,11 @@ FOUNDATION_EXPORT NSString * const ASDataControllerRowNodeKind; */ - (void)dataController:(ASDataController *)dataController didDeleteSectionsAtIndexSet:(NSIndexSet *)indexSet withAnimationOptions:(ASDataControllerAnimationOptions)animationOptions; +/** + Called for data reload. + */ +- (void)dataControllerDidReloadData:(ASDataController *)dataController; + @end /** @@ -170,9 +175,9 @@ FOUNDATION_EXPORT NSString * const ASDataControllerRowNodeKind; - (void)moveRowAtIndexPath:(NSIndexPath *)indexPath toIndexPath:(NSIndexPath *)newIndexPath withAnimationOptions:(ASDataControllerAnimationOptions)animationOptions; -- (void)reloadDataWithAnimationOptions:(ASDataControllerAnimationOptions)animationOptions completion:(void (^ _Nullable)())completion; +- (void)reloadDataWithCompletion:(void (^ _Nullable)())completion; -- (void)reloadDataImmediatelyWithAnimationOptions:(ASDataControllerAnimationOptions)animationOptions; +- (void)reloadDataImmediately; /** @name Data Querying */ diff --git a/AsyncDisplayKit/Details/ASDataController.mm b/AsyncDisplayKit/Details/ASDataController.mm index 53b37158..2b1549b6 100644 --- a/AsyncDisplayKit/Details/ASDataController.mm +++ b/AsyncDisplayKit/Details/ASDataController.mm @@ -43,6 +43,7 @@ static void *kASSizingQueueContext = &kASSizingQueueContext; BOOL _delegateDidDeleteNodes; BOOL _delegateDidInsertSections; BOOL _delegateDidDeleteSections; + BOOL _delegateDidReloadData; } @property (atomic, assign) NSUInteger batchUpdateCounter; @@ -92,6 +93,7 @@ static void *kASSizingQueueContext = &kASSizingQueueContext; _delegateDidDeleteNodes = [_delegate respondsToSelector:@selector(dataController:didDeleteNodes:atIndexPaths:withAnimationOptions:)]; _delegateDidInsertSections = [_delegate respondsToSelector:@selector(dataController:didInsertSections:atIndexSet:withAnimationOptions:)]; _delegateDidDeleteSections = [_delegate respondsToSelector:@selector(dataController:didDeleteSectionsAtIndexSet:withAnimationOptions:)]; + _delegateDidReloadData = [_delegate respondsToSelector:@selector(dataControllerDidReloadData:)]; } + (NSUInteger)parallelProcessorCount @@ -143,14 +145,30 @@ static void *kASSizingQueueContext = &kASSizingQueueContext; node.frame = CGRectMake(0.0f, 0.0f, node.calculatedSize.width, node.calculatedSize.height); } +/** + * Measures and defines the layout for each node in optimized batches on an editing queue, inserting the results into the backing store. + */ +- (void)_batchLayoutNodes:(NSArray *)nodes atIndexPaths:(NSArray *)indexPaths +{ + [self _batchLayoutNodes:nodes atIndexPaths:indexPaths andNotifyDelegate:NO withAnimationOptions:0]; +} + /** * Measures and defines the layout for each node in optimized batches on an editing queue, inserting the results into the backing store. */ - (void)_batchLayoutNodes:(NSArray *)nodes atIndexPaths:(NSArray *)indexPaths withAnimationOptions:(ASDataControllerAnimationOptions)animationOptions +{ + [self _batchLayoutNodes:nodes atIndexPaths:indexPaths andNotifyDelegate:YES withAnimationOptions:animationOptions]; +} + +/** + * Measures and defines the layout for each node in optimized batches on an editing queue, inserting the results into the backing store. + */ +- (void)_batchLayoutNodes:(NSArray *)nodes atIndexPaths:(NSArray *)indexPaths andNotifyDelegate:(BOOL)shouldNotifyDelegate withAnimationOptions:(ASDataControllerAnimationOptions)animationOptions { [self batchLayoutNodes:nodes ofKind:ASDataControllerRowNodeKind atIndexPaths:indexPaths completion:^(NSArray *nodes, NSArray *indexPaths) { // Insert finished nodes into data storage - [self _insertNodes:nodes atIndexPaths:indexPaths withAnimationOptions:animationOptions]; + [self _insertNodes:nodes atIndexPaths:indexPaths andNotifyDelegate:shouldNotifyDelegate withAnimationOptions:animationOptions]; }]; } @@ -240,6 +258,14 @@ static void *kASSizingQueueContext = &kASSizingQueueContext; }]; } +- (void)deleteAllNodesOfKind:(NSString *)kind +{ + [_editingNodes[kind] removeAllObjects]; + [_mainSerialQueue performBlockOnMainThread:^{ + [_completedNodes[kind] removeAllObjects]; + }]; +} + - (void)insertSections:(NSMutableArray *)sections ofKind:(NSString *)kind atIndexSet:(NSIndexSet *)indexSet completion:(void (^)(NSArray *sections, NSIndexSet *indexSet))completionBlock { if (indexSet.count == 0) @@ -277,6 +303,17 @@ static void *kASSizingQueueContext = &kASSizingQueueContext; #pragma mark - Internal Data Querying + Editing +/** + * Inserts the specified nodes into the given index paths and doesn't notify the delegate of newly inserted nodes. + * + * @discussion Nodes are first inserted into the editing store, then the completed store is replaced by a deep copy + * of the editing nodes. + */ +- (void)_insertNodes:(NSArray *)nodes atIndexPaths:(NSArray *)indexPaths +{ + [self _insertNodes:nodes atIndexPaths:indexPaths andNotifyDelegate:NO withAnimationOptions:0]; +} + /** * Inserts the specified nodes into the given index paths and notifies the delegate of newly inserted nodes. * @@ -285,10 +322,26 @@ static void *kASSizingQueueContext = &kASSizingQueueContext; */ - (void)_insertNodes:(NSArray *)nodes atIndexPaths:(NSArray *)indexPaths withAnimationOptions:(ASDataControllerAnimationOptions)animationOptions { - [self insertNodes:nodes ofKind:ASDataControllerRowNodeKind atIndexPaths:indexPaths completion:^(NSArray *nodes, NSArray *indexPaths) { - if (_delegateDidInsertNodes) - [_delegate dataController:self didInsertNodes:nodes atIndexPaths:indexPaths withAnimationOptions:animationOptions]; - }]; + [self _insertNodes:nodes atIndexPaths:indexPaths andNotifyDelegate:YES withAnimationOptions:animationOptions]; +} + +/** + * Inserts the specified nodes into the given index paths and notifies the delegate of newly inserted nodes. + * + * @discussion Nodes are first inserted into the editing store, then the completed store is replaced by a deep copy + * of the editing nodes. The delegate is invoked on the main thread. + */ +- (void)_insertNodes:(NSArray *)nodes atIndexPaths:(NSArray *)indexPaths andNotifyDelegate:(BOOL)shouldNotifyDelegate withAnimationOptions:(ASDataControllerAnimationOptions)animationOptions +{ + void (^completionBlock)(NSArray *nodes, NSArray *indexPaths) = nil; + if (shouldNotifyDelegate) { + completionBlock = ^(NSArray *nodes, NSArray *indexPaths) { + if (_delegateDidInsertNodes) + [_delegate dataController:self didInsertNodes:nodes atIndexPaths:indexPaths withAnimationOptions:animationOptions]; + }; + } + + [self insertNodes:nodes ofKind:ASDataControllerRowNodeKind atIndexPaths:indexPaths completion:completionBlock]; } /** @@ -305,18 +358,46 @@ static void *kASSizingQueueContext = &kASSizingQueueContext; }]; } +/** + * Inserts sections, represented as arrays, into the backing store at the given indicies and doesn't notify the delegate. + * + * @discussion The section arrays are inserted into the editing store, then a deep copy of the sections are inserted + * in the completed store on the main thread. + */ +- (void)_insertSections:(NSMutableArray *)sections atIndexSet:(NSIndexSet *)indexSet +{ + [self _insertSections:sections atIndexSet:indexSet andNotifyDelegate:NO withAnimationOptions:0]; +} + +/** + * Inserts sections, represented as arrays, into the backing store at the given indicies and doesn't notify the delegate. + * + * @discussion The section arrays are inserted into the editing store, then a deep copy of the sections are inserted + * in the completed store on the main thread. + */ +- (void)_insertSections:(NSMutableArray *)sections atIndexSet:(NSIndexSet *)indexSet withAnimationOptions:(ASDataControllerAnimationOptions)animationOptions +{ + [self _insertSections:sections atIndexSet:indexSet andNotifyDelegate:YES withAnimationOptions:animationOptions]; +} + /** * Inserts sections, represented as arrays, into the backing store at the given indicies and notifies the delegate. * * @discussion The section arrays are inserted into the editing store, then a deep copy of the sections are inserted * in the completed store on the main thread. The delegate is invoked on the main thread. */ -- (void)_insertSections:(NSMutableArray *)sections atIndexSet:(NSIndexSet *)indexSet withAnimationOptions:(ASDataControllerAnimationOptions)animationOptions +- (void)_insertSections:(NSMutableArray *)sections atIndexSet:(NSIndexSet *)indexSet andNotifyDelegate:(BOOL)shouldNotifyDelegate withAnimationOptions:(ASDataControllerAnimationOptions)animationOptions { - [self insertSections:sections ofKind:ASDataControllerRowNodeKind atIndexSet:indexSet completion:^(NSArray *sections, NSIndexSet *indexSet) { - if (_delegateDidInsertSections) - [_delegate dataController:self didInsertSections:sections atIndexSet:indexSet withAnimationOptions:animationOptions]; - }]; + + void (^completionBlock)(NSArray *sections, NSIndexSet *indexSet) = nil; + if (shouldNotifyDelegate) { + completionBlock = ^(NSArray *sections, NSIndexSet *indexSet) { + if (_delegateDidInsertSections) + [_delegate dataController:self didInsertSections:sections atIndexSet:indexSet withAnimationOptions:animationOptions]; + }; + } + + [self insertSections:sections ofKind:ASDataControllerRowNodeKind atIndexSet:indexSet completion:completionBlock]; } /** @@ -361,17 +442,17 @@ static void *kASSizingQueueContext = &kASSizingQueueContext; }]; } -- (void)reloadDataWithAnimationOptions:(ASDataControllerAnimationOptions)animationOptions completion:(void (^)())completion +- (void)reloadDataWithCompletion:(void (^)())completion { - [self _reloadDataWithAnimationOptions:animationOptions synchronously:NO completion:completion]; + [self _reloadDataSynchronously:NO completion:completion]; } -- (void)reloadDataImmediatelyWithAnimationOptions:(ASDataControllerAnimationOptions)animationOptions +- (void)reloadDataImmediately { - [self _reloadDataWithAnimationOptions:animationOptions synchronously:YES completion:nil]; + [self _reloadDataSynchronously:YES completion:nil]; } -- (void)_reloadDataWithAnimationOptions:(ASDataControllerAnimationOptions)animationOptions synchronously:(BOOL)synchronously completion:(void (^)())completion +- (void)_reloadDataSynchronously:(BOOL)synchronously completion:(void (^)())completion { [self performEditCommandWithBlock:^{ ASDisplayNodeAssertMainThread(); @@ -393,12 +474,7 @@ static void *kASSizingQueueContext = &kASSizingQueueContext; LOG(@"Edit Transaction - reloadData"); // Remove everything that existed before the reload, now that we're ready to insert replacements - NSArray *indexPaths = ASIndexPathsForMultidimensionalArray(_editingNodes[ASDataControllerRowNodeKind]); - [self _deleteNodesAtIndexPaths:indexPaths withAnimationOptions:animationOptions]; - - NSMutableArray *editingNodes = _editingNodes[ASDataControllerRowNodeKind]; - NSMutableIndexSet *indexSet = [[NSMutableIndexSet alloc] initWithIndexesInRange:NSMakeRange(0, editingNodes.count)]; - [self _deleteSectionsAtIndexSet:indexSet withAnimationOptions:animationOptions]; + [self deleteAllNodesOfKind:ASDataControllerRowNodeKind]; [self willReloadData]; @@ -408,12 +484,19 @@ static void *kASSizingQueueContext = &kASSizingQueueContext; [sections addObject:[[NSMutableArray alloc] init]]; } - [self _insertSections:sections atIndexSet:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, sectionCount)] withAnimationOptions:animationOptions]; + [self _insertSections:sections atIndexSet:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, sectionCount)]]; - [self _batchLayoutNodes:updatedNodes atIndexPaths:updatedIndexPaths withAnimationOptions:animationOptions]; + [self _batchLayoutNodes:updatedNodes atIndexPaths:updatedIndexPaths]; - if (completion) { - dispatch_async(dispatch_get_main_queue(), completion); + if (_delegateDidReloadData || completion) { + [_mainSerialQueue performBlockOnMainThread:^{ + if (_delegateDidReloadData) { + [_delegate dataControllerDidReloadData:self]; + } + if (completion) { + completion(); + } + }]; } }; diff --git a/AsyncDisplayKit/Details/ASRangeController.h b/AsyncDisplayKit/Details/ASRangeController.h index 74061f88..61ee2470 100644 --- a/AsyncDisplayKit/Details/ASRangeController.h +++ b/AsyncDisplayKit/Details/ASRangeController.h @@ -190,6 +190,13 @@ NS_ASSUME_NONNULL_BEGIN */ - (void)rangeController:(ASRangeController *)rangeController didDeleteSectionsAtIndexSet:(NSIndexSet *)indexSet withAnimationOptions:(ASDataControllerAnimationOptions)animationOptions; +/** + * Called for data reload. + * + * @param rangeController Sender. + */ +- (void)rangeControllerDidReloadData:(ASRangeController *)rangeController; + @end NS_ASSUME_NONNULL_END \ No newline at end of file diff --git a/AsyncDisplayKit/Details/ASRangeController.mm b/AsyncDisplayKit/Details/ASRangeController.mm index 0329ccfd..fa0610a0 100644 --- a/AsyncDisplayKit/Details/ASRangeController.mm +++ b/AsyncDisplayKit/Details/ASRangeController.mm @@ -276,4 +276,17 @@ }); } +- (void)dataControllerDidReloadData:(ASDataController *)dataController +{ + ASPerformBlockOnMainThread(^{ + _rangeIsValid = NO; + + // When reload data we need to make sure that _rangeTypeIndexPaths is cleared as well, + // otherwise _updateVisibleNodeIndexPaths may try to retrieve nodes from dataSource that aren't there anymore + [_rangeTypeIndexPaths removeAllObjects]; + + [_delegate rangeControllerDidReloadData:self]; + }); +} + @end diff --git a/AsyncDisplayKit/Details/ASRangeControllerBeta.mm b/AsyncDisplayKit/Details/ASRangeControllerBeta.mm index e53000d9..5239a8d8 100644 --- a/AsyncDisplayKit/Details/ASRangeControllerBeta.mm +++ b/AsyncDisplayKit/Details/ASRangeControllerBeta.mm @@ -267,4 +267,12 @@ }); } +- (void)dataControllerDidReloadData:(ASDataController *)dataController +{ + ASPerformBlockOnMainThread(^{ + _rangeIsValid = NO; + [_delegate rangeControllerDidReloadData:self]; + }); +} + @end From 8d3c32727e95098cea7e43e245cf277fa628634a Mon Sep 17 00:00:00 2001 From: Bin Liu Date: Thu, 21 Jan 2016 12:05:28 -0800 Subject: [PATCH 21/27] fix build --- AsyncDisplayKit/ASCollectionNode.h | 2 +- AsyncDisplayKit/ASCollectionView.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/AsyncDisplayKit/ASCollectionNode.h b/AsyncDisplayKit/ASCollectionNode.h index 1c236aaf..5ae61db5 100644 --- a/AsyncDisplayKit/ASCollectionNode.h +++ b/AsyncDisplayKit/ASCollectionNode.h @@ -18,7 +18,7 @@ NS_ASSUME_NONNULL_BEGIN - (instancetype)initWithCollectionViewLayout:(UICollectionViewLayout *)layout; - (instancetype)initWithFrame:(CGRect)frame collectionViewLayout:(UICollectionViewLayout *)layout; -- (instancetype)initWithFrame:(CGRect)frame collectionViewLayout:(UICollectionViewLayout *)layout layoutFacilitator:(id)layoutFacilitator; +- (instancetype)initWithFrame:(CGRect)frame collectionViewLayout:(UICollectionViewLayout *)layout layoutFacilitator:(nullable id)layoutFacilitator; @property (weak, nonatomic) id delegate; @property (weak, nonatomic) id dataSource; diff --git a/AsyncDisplayKit/ASCollectionView.h b/AsyncDisplayKit/ASCollectionView.h index f9352567..63be19b2 100644 --- a/AsyncDisplayKit/ASCollectionView.h +++ b/AsyncDisplayKit/ASCollectionView.h @@ -13,7 +13,7 @@ #import #import #import -#import +#import "ASCollectionViewLayoutFacilitatorProtocol.h" @class ASCellNode; @class ASCollectionNode; From 1965018c468b967683dd51b37c69105c1c7c313c Mon Sep 17 00:00:00 2001 From: Bin Liu Date: Thu, 21 Jan 2016 15:20:47 -0800 Subject: [PATCH 22/27] attempt to fix build --- AsyncDisplayKit.xcodeproj/project.pbxproj | 10 ++++++---- AsyncDisplayKit/ASCollectionNode.h | 2 ++ AsyncDisplayKit/ASCollectionNode.mm | 1 + AsyncDisplayKit/ASCollectionView.h | 2 +- AsyncDisplayKit/ASCollectionView.mm | 1 + .../ASCollectionViewLayoutFacilitatorProtocol.h | 0 6 files changed, 11 insertions(+), 5 deletions(-) rename AsyncDisplayKit/{Details => }/ASCollectionViewLayoutFacilitatorProtocol.h (100%) diff --git a/AsyncDisplayKit.xcodeproj/project.pbxproj b/AsyncDisplayKit.xcodeproj/project.pbxproj index bbdacf50..92c97dd2 100644 --- a/AsyncDisplayKit.xcodeproj/project.pbxproj +++ b/AsyncDisplayKit.xcodeproj/project.pbxproj @@ -357,7 +357,8 @@ ACF6ED631B178DC700DA7C62 /* ASStackLayoutSpecSnapshotTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = ACF6ED5B1B178DC700DA7C62 /* ASStackLayoutSpecSnapshotTests.mm */; }; B0F8805A1BEAEC7500D17647 /* ASTableNode.h in Headers */ = {isa = PBXBuildFile; fileRef = B0F880581BEAEC7500D17647 /* ASTableNode.h */; settings = {ATTRIBUTES = (Public, ); }; }; B0F8805B1BEAEC7500D17647 /* ASTableNode.m in Sources */ = {isa = PBXBuildFile; fileRef = B0F880591BEAEC7500D17647 /* ASTableNode.m */; }; - B13CA0F21C51653000E031AB /* ASCollectionViewLayoutFacilitatorProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = B13CA0F11C51653000E031AB /* ASCollectionViewLayoutFacilitatorProtocol.h */; }; + B13CA0F71C519E9400E031AB /* ASCollectionViewLayoutFacilitatorProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = B13CA0F61C519E9400E031AB /* ASCollectionViewLayoutFacilitatorProtocol.h */; }; + B13CA0F81C519EBA00E031AB /* ASCollectionViewLayoutFacilitatorProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = B13CA0F61C519E9400E031AB /* ASCollectionViewLayoutFacilitatorProtocol.h */; }; B35061F31B010EFD0018CF92 /* ASCellNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 055F1A3A19ABD43F004DAFF1 /* ASCellNode.h */; settings = {ATTRIBUTES = (Public, ); }; }; B35061F51B010EFD0018CF92 /* ASCollectionView.h in Headers */ = {isa = PBXBuildFile; fileRef = AC3C4A4F1A1139C100143C57 /* ASCollectionView.h */; settings = {ATTRIBUTES = (Public, ); }; }; B35061F61B010EFD0018CF92 /* ASCollectionView.mm in Sources */ = {isa = PBXBuildFile; fileRef = AC3C4A501A1139C100143C57 /* ASCollectionView.mm */; }; @@ -766,7 +767,7 @@ ACF6ED5B1B178DC700DA7C62 /* ASStackLayoutSpecSnapshotTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASStackLayoutSpecSnapshotTests.mm; sourceTree = ""; }; B0F880581BEAEC7500D17647 /* ASTableNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASTableNode.h; sourceTree = ""; }; B0F880591BEAEC7500D17647 /* ASTableNode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASTableNode.m; sourceTree = ""; }; - B13CA0F11C51653000E031AB /* ASCollectionViewLayoutFacilitatorProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASCollectionViewLayoutFacilitatorProtocol.h; sourceTree = ""; }; + B13CA0F61C519E9400E031AB /* ASCollectionViewLayoutFacilitatorProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASCollectionViewLayoutFacilitatorProtocol.h; sourceTree = ""; }; B35061DA1B010EDF0018CF92 /* AsyncDisplayKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = AsyncDisplayKit.framework; sourceTree = BUILT_PRODUCTS_DIR; }; B35061DD1B010EDF0018CF92 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = "../AsyncDisplayKit-iOS/Info.plist"; sourceTree = ""; }; CC7FD9DC1BB5E962005CCB2B /* ASPhotosFrameworkImageRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASPhotosFrameworkImageRequest.h; sourceTree = ""; }; @@ -910,6 +911,7 @@ AC3C4A4F1A1139C100143C57 /* ASCollectionView.h */, AC3C4A501A1139C100143C57 /* ASCollectionView.mm */, AC3C4A531A113EEC00143C57 /* ASCollectionViewProtocols.h */, + B13CA0F61C519E9400E031AB /* ASCollectionViewLayoutFacilitatorProtocol.h */, DEC146B41C37A16A004A0EE7 /* ASCollectionInternal.h */, DEC146B51C37A16A004A0EE7 /* ASCollectionInternal.m */, 058D09D5195D050800B7D73C /* ASControlNode.h */, @@ -1037,7 +1039,6 @@ 299DA1A81A828D2900162D41 /* ASBatchContext.mm */, 205F0E1B1B373A2C007741D0 /* ASCollectionViewLayoutController.h */, 205F0E1C1B373A2C007741D0 /* ASCollectionViewLayoutController.mm */, - B13CA0F11C51653000E031AB /* ASCollectionViewLayoutFacilitatorProtocol.h */, 05A6D05819D0EB64002DD95E /* ASDealloc2MainObject.h */, 05A6D05919D0EB64002DD95E /* ASDealloc2MainObject.m */, 4640521B1A3F83C40061C0BA /* ASFlowLayoutController.h */, @@ -1279,7 +1280,7 @@ 058D0A72195D05F800B7D73C /* _ASCoreAnimationExtras.h in Headers */, 058D0A53195D05DC00B7D73C /* _ASDisplayLayer.h in Headers */, 058D0A55195D05DC00B7D73C /* _ASDisplayView.h in Headers */, - B13CA0F21C51653000E031AB /* ASCollectionViewLayoutFacilitatorProtocol.h in Headers */, + B13CA0F71C519E9400E031AB /* ASCollectionViewLayoutFacilitatorProtocol.h in Headers */, 058D0A74195D05F800B7D73C /* _ASPendingState.h in Headers */, 9C5586691BD549CB00B50E3A /* ASAsciiArtBoxCreator.h in Headers */, 058D0A76195D05F900B7D73C /* _ASScopeTimer.h in Headers */, @@ -1478,6 +1479,7 @@ B35062041B010EFD0018CF92 /* ASMultiplexImageNode.h in Headers */, DECBD6E81BE56E1900CF4905 /* ASButtonNode.h in Headers */, B35062241B010EFD0018CF92 /* ASMutableAttributedStringBuilder.h in Headers */, + B13CA0F81C519EBA00E031AB /* ASCollectionViewLayoutFacilitatorProtocol.h in Headers */, B35062061B010EFD0018CF92 /* ASNetworkImageNode.h in Headers */, 34EFC76C1B701CED00AD841F /* ASOverlayLayoutSpec.h in Headers */, B35062261B010EFD0018CF92 /* ASRangeController.h in Headers */, diff --git a/AsyncDisplayKit/ASCollectionNode.h b/AsyncDisplayKit/ASCollectionNode.h index 5ae61db5..4a49be16 100644 --- a/AsyncDisplayKit/ASCollectionNode.h +++ b/AsyncDisplayKit/ASCollectionNode.h @@ -8,6 +8,8 @@ #import +@protocol ASCollectionViewLayoutFacilitatorProtocol; + NS_ASSUME_NONNULL_BEGIN /** diff --git a/AsyncDisplayKit/ASCollectionNode.mm b/AsyncDisplayKit/ASCollectionNode.mm index a8f2055f..5bed1a1b 100644 --- a/AsyncDisplayKit/ASCollectionNode.mm +++ b/AsyncDisplayKit/ASCollectionNode.mm @@ -8,6 +8,7 @@ #import "ASCollectionNode.h" #import "ASCollectionInternal.h" +#import "ASCollectionViewLayoutFacilitatorProtocol.h" #import "ASDisplayNode+Subclasses.h" #import "ASRangeController.h" #include diff --git a/AsyncDisplayKit/ASCollectionView.h b/AsyncDisplayKit/ASCollectionView.h index 63be19b2..32d42e32 100644 --- a/AsyncDisplayKit/ASCollectionView.h +++ b/AsyncDisplayKit/ASCollectionView.h @@ -13,13 +13,13 @@ #import #import #import -#import "ASCollectionViewLayoutFacilitatorProtocol.h" @class ASCellNode; @class ASCollectionNode; @protocol ASCollectionDataSource; @protocol ASCollectionDelegate; @protocol ASCollectionViewLayoutInspecting; +@protocol ASCollectionViewLayoutFacilitatorProtocol; NS_ASSUME_NONNULL_BEGIN diff --git a/AsyncDisplayKit/ASCollectionView.mm b/AsyncDisplayKit/ASCollectionView.mm index 83065aa3..6cb958e6 100644 --- a/AsyncDisplayKit/ASCollectionView.mm +++ b/AsyncDisplayKit/ASCollectionView.mm @@ -13,6 +13,7 @@ #import "ASCollectionDataController.h" #import "ASCollectionViewLayoutController.h" #import "ASCollectionViewFlowLayoutInspector.h" +#import "ASCollectionViewLayoutFacilitatorProtocol.h" #import "ASDisplayNode+FrameworkPrivate.h" #import "ASDisplayNode+Beta.h" #import "ASInternalHelpers.h" diff --git a/AsyncDisplayKit/Details/ASCollectionViewLayoutFacilitatorProtocol.h b/AsyncDisplayKit/ASCollectionViewLayoutFacilitatorProtocol.h similarity index 100% rename from AsyncDisplayKit/Details/ASCollectionViewLayoutFacilitatorProtocol.h rename to AsyncDisplayKit/ASCollectionViewLayoutFacilitatorProtocol.h From b2db6cce4d17e9280fed0b7588b2e092629ce25b Mon Sep 17 00:00:00 2001 From: Bin Liu Date: Thu, 21 Jan 2016 22:39:27 -0800 Subject: [PATCH 23/27] remove public interface for ASCV with facilitator --- AsyncDisplayKit.xcodeproj/project.pbxproj | 6 ++++++ AsyncDisplayKit/ASCollectionNode+Beta.h | 19 +++++++++++++++++++ AsyncDisplayKit/ASCollectionNode.h | 1 - AsyncDisplayKit/ASCollectionView.h | 1 - AsyncDisplayKit/ASCollectionView.mm | 7 ------- 5 files changed, 25 insertions(+), 9 deletions(-) create mode 100644 AsyncDisplayKit/ASCollectionNode+Beta.h diff --git a/AsyncDisplayKit.xcodeproj/project.pbxproj b/AsyncDisplayKit.xcodeproj/project.pbxproj index 92c97dd2..bda1bbc5 100644 --- a/AsyncDisplayKit.xcodeproj/project.pbxproj +++ b/AsyncDisplayKit.xcodeproj/project.pbxproj @@ -359,6 +359,8 @@ B0F8805B1BEAEC7500D17647 /* ASTableNode.m in Sources */ = {isa = PBXBuildFile; fileRef = B0F880591BEAEC7500D17647 /* ASTableNode.m */; }; B13CA0F71C519E9400E031AB /* ASCollectionViewLayoutFacilitatorProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = B13CA0F61C519E9400E031AB /* ASCollectionViewLayoutFacilitatorProtocol.h */; }; B13CA0F81C519EBA00E031AB /* ASCollectionViewLayoutFacilitatorProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = B13CA0F61C519E9400E031AB /* ASCollectionViewLayoutFacilitatorProtocol.h */; }; + B13CA1001C52004900E031AB /* ASCollectionNode+Beta.h in Headers */ = {isa = PBXBuildFile; fileRef = B13CA0FF1C52004900E031AB /* ASCollectionNode+Beta.h */; }; + B13CA1011C52004900E031AB /* ASCollectionNode+Beta.h in Headers */ = {isa = PBXBuildFile; fileRef = B13CA0FF1C52004900E031AB /* ASCollectionNode+Beta.h */; }; B35061F31B010EFD0018CF92 /* ASCellNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 055F1A3A19ABD43F004DAFF1 /* ASCellNode.h */; settings = {ATTRIBUTES = (Public, ); }; }; B35061F51B010EFD0018CF92 /* ASCollectionView.h in Headers */ = {isa = PBXBuildFile; fileRef = AC3C4A4F1A1139C100143C57 /* ASCollectionView.h */; settings = {ATTRIBUTES = (Public, ); }; }; B35061F61B010EFD0018CF92 /* ASCollectionView.mm in Sources */ = {isa = PBXBuildFile; fileRef = AC3C4A501A1139C100143C57 /* ASCollectionView.mm */; }; @@ -768,6 +770,7 @@ B0F880581BEAEC7500D17647 /* ASTableNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASTableNode.h; sourceTree = ""; }; B0F880591BEAEC7500D17647 /* ASTableNode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASTableNode.m; sourceTree = ""; }; B13CA0F61C519E9400E031AB /* ASCollectionViewLayoutFacilitatorProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASCollectionViewLayoutFacilitatorProtocol.h; sourceTree = ""; }; + B13CA0FF1C52004900E031AB /* ASCollectionNode+Beta.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "ASCollectionNode+Beta.h"; sourceTree = ""; }; B35061DA1B010EDF0018CF92 /* AsyncDisplayKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = AsyncDisplayKit.framework; sourceTree = BUILT_PRODUCTS_DIR; }; B35061DD1B010EDF0018CF92 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = "../AsyncDisplayKit-iOS/Info.plist"; sourceTree = ""; }; CC7FD9DC1BB5E962005CCB2B /* ASPhotosFrameworkImageRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASPhotosFrameworkImageRequest.h; sourceTree = ""; }; @@ -908,6 +911,7 @@ AC6456071B0A335000CF11B8 /* ASCellNode.m */, 18C2ED7C1B9B7DE800F627B3 /* ASCollectionNode.h */, 18C2ED7D1B9B7DE800F627B3 /* ASCollectionNode.mm */, + B13CA0FF1C52004900E031AB /* ASCollectionNode+Beta.h */, AC3C4A4F1A1139C100143C57 /* ASCollectionView.h */, AC3C4A501A1139C100143C57 /* ASCollectionView.mm */, AC3C4A531A113EEC00143C57 /* ASCollectionViewProtocols.h */, @@ -1351,6 +1355,7 @@ AC026B6F1BD57DBF00BBC17E /* _ASHierarchyChangeSet.h in Headers */, 0516FA3D1A15563400B4EBED /* ASLog.h in Headers */, 257754AA1BEE44CD00737CA5 /* ASTextKitEntityAttribute.h in Headers */, + B13CA1001C52004900E031AB /* ASCollectionNode+Beta.h in Headers */, 0442850D1BAA64EC00D16268 /* ASMultidimensionalArrayUtils.h in Headers */, 0516FA401A1563D200B4EBED /* ASMultiplexImageNode.h in Headers */, 058D0A59195D05DC00B7D73C /* ASMutableAttributedStringBuilder.h in Headers */, @@ -1405,6 +1410,7 @@ B350623C1B010EFD0018CF92 /* _ASAsyncTransaction.h in Headers */, B350623E1B010EFD0018CF92 /* _ASAsyncTransactionContainer+Private.h in Headers */, B350623F1B010EFD0018CF92 /* _ASAsyncTransactionContainer.h in Headers */, + B13CA1011C52004900E031AB /* ASCollectionNode+Beta.h in Headers */, DECC2ECE1C35C1C600388446 /* ASRangeControllerBeta.h in Headers */, 254C6B7E1BF94DF4003EC431 /* ASTextKitTailTruncater.h in Headers */, B35062411B010EFD0018CF92 /* _ASAsyncTransactionGroup.h in Headers */, diff --git a/AsyncDisplayKit/ASCollectionNode+Beta.h b/AsyncDisplayKit/ASCollectionNode+Beta.h new file mode 100644 index 00000000..eeac22b3 --- /dev/null +++ b/AsyncDisplayKit/ASCollectionNode+Beta.h @@ -0,0 +1,19 @@ +/* Copyright (c) 2014-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +@protocol ASCollectionViewLayoutFacilitatorProtocol; + +NS_ASSUME_NONNULL_BEGIN + +@interface ASCollectionNode (Beta) + +- (instancetype)initWithFrame:(CGRect)frame collectionViewLayout:(UICollectionViewLayout *)layout layoutFacilitator:(nullable id)layoutFacilitator; + +@end + +NS_ASSUME_NONNULL_END diff --git a/AsyncDisplayKit/ASCollectionNode.h b/AsyncDisplayKit/ASCollectionNode.h index 4a49be16..1b140873 100644 --- a/AsyncDisplayKit/ASCollectionNode.h +++ b/AsyncDisplayKit/ASCollectionNode.h @@ -20,7 +20,6 @@ NS_ASSUME_NONNULL_BEGIN - (instancetype)initWithCollectionViewLayout:(UICollectionViewLayout *)layout; - (instancetype)initWithFrame:(CGRect)frame collectionViewLayout:(UICollectionViewLayout *)layout; -- (instancetype)initWithFrame:(CGRect)frame collectionViewLayout:(UICollectionViewLayout *)layout layoutFacilitator:(nullable id)layoutFacilitator; @property (weak, nonatomic) id delegate; @property (weak, nonatomic) id dataSource; diff --git a/AsyncDisplayKit/ASCollectionView.h b/AsyncDisplayKit/ASCollectionView.h index 32d42e32..418d22c2 100644 --- a/AsyncDisplayKit/ASCollectionView.h +++ b/AsyncDisplayKit/ASCollectionView.h @@ -44,7 +44,6 @@ NS_ASSUME_NONNULL_BEGIN */ - (instancetype)initWithCollectionViewLayout:(UICollectionViewLayout *)layout; - (instancetype)initWithFrame:(CGRect)frame collectionViewLayout:(UICollectionViewLayout *)layout; -- (instancetype)initWithFrame:(CGRect)frame collectionViewLayout:(UICollectionViewLayout *)layout layoutFacilitator:(id)layoutFacilitator; // The corresponding ASCollectionNode, which exists even if directly allocating & handling the view class. @property (nonatomic, weak, readonly) ASCollectionNode *collectionNode; diff --git a/AsyncDisplayKit/ASCollectionView.mm b/AsyncDisplayKit/ASCollectionView.mm index 6cb958e6..2b588d08 100644 --- a/AsyncDisplayKit/ASCollectionView.mm +++ b/AsyncDisplayKit/ASCollectionView.mm @@ -140,13 +140,6 @@ static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell"; return [self _initWithFrame:frame collectionViewLayout:layout ownedByNode:NO]; } -- (instancetype)initWithFrame:(CGRect)frame collectionViewLayout:(UICollectionViewLayout *)layout layoutFacilitator:(id)layoutFacilitator -{ - self = [self _initWithFrame:frame collectionViewLayout:layout ownedByNode:NO]; - _layoutFacilitator = layoutFacilitator; - return self; -} - // FIXME: This method is deprecated and will probably be removed in or shortly after 2.0. - (instancetype)initWithFrame:(CGRect)frame collectionViewLayout:(UICollectionViewLayout *)layout asyncDataFetching:(BOOL)asyncDataFetchingEnabled { From 475c9c1e2ca1fb4a410ac09091944198837675a2 Mon Sep 17 00:00:00 2001 From: Aaron Schubert Date: Fri, 22 Jan 2016 09:38:32 +0000 Subject: [PATCH 24/27] Check to see if Clang code coverage is interfering with GCC --- AsyncDisplayKit.xcodeproj/project.pbxproj | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/AsyncDisplayKit.xcodeproj/project.pbxproj b/AsyncDisplayKit.xcodeproj/project.pbxproj index bda1bbc5..40153a87 100644 --- a/AsyncDisplayKit.xcodeproj/project.pbxproj +++ b/AsyncDisplayKit.xcodeproj/project.pbxproj @@ -2021,6 +2021,7 @@ ALWAYS_SEARCH_USER_PATHS = NO; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_CODE_COVERAGE = NO; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BOOL_CONVERSION = YES; @@ -2061,6 +2062,7 @@ ALWAYS_SEARCH_USER_PATHS = NO; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_CODE_COVERAGE = NO; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BOOL_CONVERSION = YES; @@ -2092,7 +2094,7 @@ isa = XCBuildConfiguration; buildSettings = { APPLICATION_EXTENSION_API_ONLY = YES; - CLANG_ENABLE_CODE_COVERAGE = YES; + CLANG_ENABLE_CODE_COVERAGE = NO; DSTROOT = /tmp/AsyncDisplayKit.dst; GCC_INPUT_FILETYPE = automatic; GCC_INSTRUMENT_PROGRAM_FLOW_ARCS = NO; @@ -2113,7 +2115,7 @@ isa = XCBuildConfiguration; buildSettings = { APPLICATION_EXTENSION_API_ONLY = YES; - CLANG_ENABLE_CODE_COVERAGE = YES; + CLANG_ENABLE_CODE_COVERAGE = NO; DSTROOT = /tmp/AsyncDisplayKit.dst; GCC_INPUT_FILETYPE = automatic; GCC_INSTRUMENT_PROGRAM_FLOW_ARCS = NO; From 423a5b0752e90d09c73e361509266eb2f2292f84 Mon Sep 17 00:00:00 2001 From: Aaron Schubert Date: Fri, 22 Jan 2016 12:22:32 +0000 Subject: [PATCH 25/27] Enabled Xcode 7 code coverage on project --- .../xcshareddata/xcschemes/AsyncDisplayKit-iOS.xcscheme | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/AsyncDisplayKit.xcodeproj/xcshareddata/xcschemes/AsyncDisplayKit-iOS.xcscheme b/AsyncDisplayKit.xcodeproj/xcshareddata/xcschemes/AsyncDisplayKit-iOS.xcscheme index c40014ed..50760cce 100644 --- a/AsyncDisplayKit.xcodeproj/xcshareddata/xcschemes/AsyncDisplayKit-iOS.xcscheme +++ b/AsyncDisplayKit.xcodeproj/xcshareddata/xcschemes/AsyncDisplayKit-iOS.xcscheme @@ -26,7 +26,8 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" - shouldUseLaunchSchemeArgsEnv = "YES"> + shouldUseLaunchSchemeArgsEnv = "YES" + codeCoverageEnabled = "YES"> From 4817484f47513ac13cefc708b1325d2ed98ebf21 Mon Sep 17 00:00:00 2001 From: Aaron Schubert Date: Fri, 22 Jan 2016 14:22:40 +0000 Subject: [PATCH 26/27] Enable clang code coverage --- AsyncDisplayKit.xcodeproj/project.pbxproj | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/AsyncDisplayKit.xcodeproj/project.pbxproj b/AsyncDisplayKit.xcodeproj/project.pbxproj index 40153a87..ddf50cad 100644 --- a/AsyncDisplayKit.xcodeproj/project.pbxproj +++ b/AsyncDisplayKit.xcodeproj/project.pbxproj @@ -2094,7 +2094,7 @@ isa = XCBuildConfiguration; buildSettings = { APPLICATION_EXTENSION_API_ONLY = YES; - CLANG_ENABLE_CODE_COVERAGE = NO; + CLANG_ENABLE_CODE_COVERAGE = YES; DSTROOT = /tmp/AsyncDisplayKit.dst; GCC_INPUT_FILETYPE = automatic; GCC_INSTRUMENT_PROGRAM_FLOW_ARCS = NO; @@ -2115,7 +2115,7 @@ isa = XCBuildConfiguration; buildSettings = { APPLICATION_EXTENSION_API_ONLY = YES; - CLANG_ENABLE_CODE_COVERAGE = NO; + CLANG_ENABLE_CODE_COVERAGE = YES; DSTROOT = /tmp/AsyncDisplayKit.dst; GCC_INPUT_FILETYPE = automatic; GCC_INSTRUMENT_PROGRAM_FLOW_ARCS = NO; @@ -2137,6 +2137,7 @@ baseConfigurationReference = FB07EABBCF28656C6297BC2D /* Pods-AsyncDisplayKitTests.debug.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; + CLANG_ENABLE_CODE_COVERAGE = YES; FRAMEWORK_SEARCH_PATHS = ( "$(SDKROOT)/Developer/Library/Frameworks", "$(inherited)", @@ -2166,6 +2167,7 @@ baseConfigurationReference = D3779BCFF841AD3EB56537ED /* Pods-AsyncDisplayKitTests.release.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; + CLANG_ENABLE_CODE_COVERAGE = YES; FRAMEWORK_SEARCH_PATHS = ( "$(SDKROOT)/Developer/Library/Frameworks", "$(inherited)", @@ -2192,6 +2194,7 @@ B35061EE1B010EDF0018CF92 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { + CLANG_ENABLE_CODE_COVERAGE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CURRENT_PROJECT_VERSION = 1; @@ -2224,6 +2227,7 @@ B35061EF1B010EDF0018CF92 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { + CLANG_ENABLE_CODE_COVERAGE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; From 83aaa4637e51be31f47038cefd81691b54c24f5b Mon Sep 17 00:00:00 2001 From: Scott Goodson Date: Fri, 22 Jan 2016 20:33:33 -0800 Subject: [PATCH 27/27] Revert "ASDataController now handles reloadData more efficiently and notify its delegate once instead of a series of deletes and inserts" This reverts commit 2e4d716e0b65465d9c65b5821668c38e5fa956c9. Possible issue with this commit. --- AsyncDisplayKit/ASCollectionView.mm | 23 +-- AsyncDisplayKit/ASTableView.mm | 20 +-- .../Details/ASCollectionDataController.mm | 2 +- AsyncDisplayKit/Details/ASDataController.h | 9 +- AsyncDisplayKit/Details/ASDataController.mm | 133 ++++-------------- AsyncDisplayKit/Details/ASRangeController.h | 7 - AsyncDisplayKit/Details/ASRangeController.mm | 13 -- .../Details/ASRangeControllerBeta.mm | 8 -- 8 files changed, 36 insertions(+), 179 deletions(-) diff --git a/AsyncDisplayKit/ASCollectionView.mm b/AsyncDisplayKit/ASCollectionView.mm index 4334ee5d..2b588d08 100644 --- a/AsyncDisplayKit/ASCollectionView.mm +++ b/AsyncDisplayKit/ASCollectionView.mm @@ -250,7 +250,7 @@ static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell"; _superIsPendingDataLoad = YES; [super reloadData]; }); - [_dataController reloadDataWithCompletion:completion]; + [_dataController reloadDataWithAnimationOptions:kASCollectionViewAnimationNone completion:completion]; } - (void)reloadData @@ -262,7 +262,7 @@ static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell"; { ASDisplayNodeAssertMainThread(); _superIsPendingDataLoad = YES; - [_dataController reloadDataImmediately]; + [_dataController reloadDataImmediatelyWithAnimationOptions:kASCollectionViewAnimationNone]; [super reloadData]; } @@ -938,25 +938,6 @@ static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell"; } } -- (void)rangeControllerDidReloadData:(ASRangeController *)rangeController -{ - ASDisplayNodeAssertMainThread(); - - if (!self.asyncDataSource || _superIsPendingDataLoad) { - return; // if the asyncDataSource has become invalid while we are processing, ignore this request to avoid crashes - } - - if (_performingBatchUpdates) { - [_batchUpdateBlocks addObject:^{ - [super reloadData]; - }]; - } else { - [UIView performWithoutAnimation:^{ - [super reloadData]; - }]; - } -} - #pragma mark - ASCellNodeDelegate - (void)nodeDidRelayout:(ASCellNode *)node sizeChanged:(BOOL)sizeChanged diff --git a/AsyncDisplayKit/ASTableView.mm b/AsyncDisplayKit/ASTableView.mm index 26248fb8..6d5c40e8 100644 --- a/AsyncDisplayKit/ASTableView.mm +++ b/AsyncDisplayKit/ASTableView.mm @@ -298,7 +298,10 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell"; - (void)reloadDataWithCompletion:(void (^)())completion { - [_dataController reloadDataWithCompletion:completion]; + ASPerformBlockOnMainThread(^{ + [super reloadData]; + }); + [_dataController reloadDataWithAnimationOptions:UITableViewRowAnimationNone completion:completion]; } - (void)reloadData @@ -309,7 +312,8 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell"; - (void)reloadDataImmediately { ASDisplayNodeAssertMainThread(); - [_dataController reloadDataImmediately]; + [_dataController reloadDataImmediatelyWithAnimationOptions:UITableViewRowAnimationNone]; + [super reloadData]; } - (void)setTuningParameters:(ASRangeTuningParameters)tuningParameters forRangeType:(ASLayoutRangeType)rangeType @@ -841,18 +845,6 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell"; }); } -- (void)rangeControllerDidReloadData:(ASRangeController *)rangeController -{ - ASDisplayNodeAssertMainThread(); - LOG(@"UITableView reloadData"); - - if (!self.asyncDataSource) { - return; // if the asyncDataSource has become invalid while we are processing, ignore this request to avoid crashes - } - - [super reloadData]; -} - #pragma mark - ASDataControllerDelegate - (ASCellNode *)dataController:(ASDataController *)dataController nodeAtIndexPath:(NSIndexPath *)indexPath diff --git a/AsyncDisplayKit/Details/ASCollectionDataController.mm b/AsyncDisplayKit/Details/ASCollectionDataController.mm index 5b433104..9e51ee6a 100644 --- a/AsyncDisplayKit/Details/ASCollectionDataController.mm +++ b/AsyncDisplayKit/Details/ASCollectionDataController.mm @@ -55,7 +55,7 @@ - (void)willReloadData { - [_pendingNodes enumerateKeysAndObjectsUsingBlock:^(NSString *kind, NSMutableArray *nodes, BOOL *stop) { + [_pendingNodes enumerateKeysAndObjectsUsingBlock:^(NSString *kind, NSMutableArray *nodes, BOOL *stop) { // Remove everything that existed before the reload, now that we're ready to insert replacements NSArray *indexPaths = [self indexPathsForEditingNodesOfKind:kind]; [self deleteNodesOfKind:kind atIndexPaths:indexPaths completion:nil]; diff --git a/AsyncDisplayKit/Details/ASDataController.h b/AsyncDisplayKit/Details/ASDataController.h index 113c5826..5710b22b 100644 --- a/AsyncDisplayKit/Details/ASDataController.h +++ b/AsyncDisplayKit/Details/ASDataController.h @@ -94,11 +94,6 @@ FOUNDATION_EXPORT NSString * const ASDataControllerRowNodeKind; */ - (void)dataController:(ASDataController *)dataController didDeleteSectionsAtIndexSet:(NSIndexSet *)indexSet withAnimationOptions:(ASDataControllerAnimationOptions)animationOptions; -/** - Called for data reload. - */ -- (void)dataControllerDidReloadData:(ASDataController *)dataController; - @end /** @@ -175,9 +170,9 @@ FOUNDATION_EXPORT NSString * const ASDataControllerRowNodeKind; - (void)moveRowAtIndexPath:(NSIndexPath *)indexPath toIndexPath:(NSIndexPath *)newIndexPath withAnimationOptions:(ASDataControllerAnimationOptions)animationOptions; -- (void)reloadDataWithCompletion:(void (^ _Nullable)())completion; +- (void)reloadDataWithAnimationOptions:(ASDataControllerAnimationOptions)animationOptions completion:(void (^ _Nullable)())completion; -- (void)reloadDataImmediately; +- (void)reloadDataImmediatelyWithAnimationOptions:(ASDataControllerAnimationOptions)animationOptions; /** @name Data Querying */ diff --git a/AsyncDisplayKit/Details/ASDataController.mm b/AsyncDisplayKit/Details/ASDataController.mm index 2b1549b6..53b37158 100644 --- a/AsyncDisplayKit/Details/ASDataController.mm +++ b/AsyncDisplayKit/Details/ASDataController.mm @@ -43,7 +43,6 @@ static void *kASSizingQueueContext = &kASSizingQueueContext; BOOL _delegateDidDeleteNodes; BOOL _delegateDidInsertSections; BOOL _delegateDidDeleteSections; - BOOL _delegateDidReloadData; } @property (atomic, assign) NSUInteger batchUpdateCounter; @@ -93,7 +92,6 @@ static void *kASSizingQueueContext = &kASSizingQueueContext; _delegateDidDeleteNodes = [_delegate respondsToSelector:@selector(dataController:didDeleteNodes:atIndexPaths:withAnimationOptions:)]; _delegateDidInsertSections = [_delegate respondsToSelector:@selector(dataController:didInsertSections:atIndexSet:withAnimationOptions:)]; _delegateDidDeleteSections = [_delegate respondsToSelector:@selector(dataController:didDeleteSectionsAtIndexSet:withAnimationOptions:)]; - _delegateDidReloadData = [_delegate respondsToSelector:@selector(dataControllerDidReloadData:)]; } + (NSUInteger)parallelProcessorCount @@ -145,30 +143,14 @@ static void *kASSizingQueueContext = &kASSizingQueueContext; node.frame = CGRectMake(0.0f, 0.0f, node.calculatedSize.width, node.calculatedSize.height); } -/** - * Measures and defines the layout for each node in optimized batches on an editing queue, inserting the results into the backing store. - */ -- (void)_batchLayoutNodes:(NSArray *)nodes atIndexPaths:(NSArray *)indexPaths -{ - [self _batchLayoutNodes:nodes atIndexPaths:indexPaths andNotifyDelegate:NO withAnimationOptions:0]; -} - /** * Measures and defines the layout for each node in optimized batches on an editing queue, inserting the results into the backing store. */ - (void)_batchLayoutNodes:(NSArray *)nodes atIndexPaths:(NSArray *)indexPaths withAnimationOptions:(ASDataControllerAnimationOptions)animationOptions -{ - [self _batchLayoutNodes:nodes atIndexPaths:indexPaths andNotifyDelegate:YES withAnimationOptions:animationOptions]; -} - -/** - * Measures and defines the layout for each node in optimized batches on an editing queue, inserting the results into the backing store. - */ -- (void)_batchLayoutNodes:(NSArray *)nodes atIndexPaths:(NSArray *)indexPaths andNotifyDelegate:(BOOL)shouldNotifyDelegate withAnimationOptions:(ASDataControllerAnimationOptions)animationOptions { [self batchLayoutNodes:nodes ofKind:ASDataControllerRowNodeKind atIndexPaths:indexPaths completion:^(NSArray *nodes, NSArray *indexPaths) { // Insert finished nodes into data storage - [self _insertNodes:nodes atIndexPaths:indexPaths andNotifyDelegate:shouldNotifyDelegate withAnimationOptions:animationOptions]; + [self _insertNodes:nodes atIndexPaths:indexPaths withAnimationOptions:animationOptions]; }]; } @@ -258,14 +240,6 @@ static void *kASSizingQueueContext = &kASSizingQueueContext; }]; } -- (void)deleteAllNodesOfKind:(NSString *)kind -{ - [_editingNodes[kind] removeAllObjects]; - [_mainSerialQueue performBlockOnMainThread:^{ - [_completedNodes[kind] removeAllObjects]; - }]; -} - - (void)insertSections:(NSMutableArray *)sections ofKind:(NSString *)kind atIndexSet:(NSIndexSet *)indexSet completion:(void (^)(NSArray *sections, NSIndexSet *indexSet))completionBlock { if (indexSet.count == 0) @@ -303,17 +277,6 @@ static void *kASSizingQueueContext = &kASSizingQueueContext; #pragma mark - Internal Data Querying + Editing -/** - * Inserts the specified nodes into the given index paths and doesn't notify the delegate of newly inserted nodes. - * - * @discussion Nodes are first inserted into the editing store, then the completed store is replaced by a deep copy - * of the editing nodes. - */ -- (void)_insertNodes:(NSArray *)nodes atIndexPaths:(NSArray *)indexPaths -{ - [self _insertNodes:nodes atIndexPaths:indexPaths andNotifyDelegate:NO withAnimationOptions:0]; -} - /** * Inserts the specified nodes into the given index paths and notifies the delegate of newly inserted nodes. * @@ -322,26 +285,10 @@ static void *kASSizingQueueContext = &kASSizingQueueContext; */ - (void)_insertNodes:(NSArray *)nodes atIndexPaths:(NSArray *)indexPaths withAnimationOptions:(ASDataControllerAnimationOptions)animationOptions { - [self _insertNodes:nodes atIndexPaths:indexPaths andNotifyDelegate:YES withAnimationOptions:animationOptions]; -} - -/** - * Inserts the specified nodes into the given index paths and notifies the delegate of newly inserted nodes. - * - * @discussion Nodes are first inserted into the editing store, then the completed store is replaced by a deep copy - * of the editing nodes. The delegate is invoked on the main thread. - */ -- (void)_insertNodes:(NSArray *)nodes atIndexPaths:(NSArray *)indexPaths andNotifyDelegate:(BOOL)shouldNotifyDelegate withAnimationOptions:(ASDataControllerAnimationOptions)animationOptions -{ - void (^completionBlock)(NSArray *nodes, NSArray *indexPaths) = nil; - if (shouldNotifyDelegate) { - completionBlock = ^(NSArray *nodes, NSArray *indexPaths) { - if (_delegateDidInsertNodes) - [_delegate dataController:self didInsertNodes:nodes atIndexPaths:indexPaths withAnimationOptions:animationOptions]; - }; - } - - [self insertNodes:nodes ofKind:ASDataControllerRowNodeKind atIndexPaths:indexPaths completion:completionBlock]; + [self insertNodes:nodes ofKind:ASDataControllerRowNodeKind atIndexPaths:indexPaths completion:^(NSArray *nodes, NSArray *indexPaths) { + if (_delegateDidInsertNodes) + [_delegate dataController:self didInsertNodes:nodes atIndexPaths:indexPaths withAnimationOptions:animationOptions]; + }]; } /** @@ -358,46 +305,18 @@ static void *kASSizingQueueContext = &kASSizingQueueContext; }]; } -/** - * Inserts sections, represented as arrays, into the backing store at the given indicies and doesn't notify the delegate. - * - * @discussion The section arrays are inserted into the editing store, then a deep copy of the sections are inserted - * in the completed store on the main thread. - */ -- (void)_insertSections:(NSMutableArray *)sections atIndexSet:(NSIndexSet *)indexSet -{ - [self _insertSections:sections atIndexSet:indexSet andNotifyDelegate:NO withAnimationOptions:0]; -} - -/** - * Inserts sections, represented as arrays, into the backing store at the given indicies and doesn't notify the delegate. - * - * @discussion The section arrays are inserted into the editing store, then a deep copy of the sections are inserted - * in the completed store on the main thread. - */ -- (void)_insertSections:(NSMutableArray *)sections atIndexSet:(NSIndexSet *)indexSet withAnimationOptions:(ASDataControllerAnimationOptions)animationOptions -{ - [self _insertSections:sections atIndexSet:indexSet andNotifyDelegate:YES withAnimationOptions:animationOptions]; -} - /** * Inserts sections, represented as arrays, into the backing store at the given indicies and notifies the delegate. * * @discussion The section arrays are inserted into the editing store, then a deep copy of the sections are inserted * in the completed store on the main thread. The delegate is invoked on the main thread. */ -- (void)_insertSections:(NSMutableArray *)sections atIndexSet:(NSIndexSet *)indexSet andNotifyDelegate:(BOOL)shouldNotifyDelegate withAnimationOptions:(ASDataControllerAnimationOptions)animationOptions +- (void)_insertSections:(NSMutableArray *)sections atIndexSet:(NSIndexSet *)indexSet withAnimationOptions:(ASDataControllerAnimationOptions)animationOptions { - - void (^completionBlock)(NSArray *sections, NSIndexSet *indexSet) = nil; - if (shouldNotifyDelegate) { - completionBlock = ^(NSArray *sections, NSIndexSet *indexSet) { - if (_delegateDidInsertSections) - [_delegate dataController:self didInsertSections:sections atIndexSet:indexSet withAnimationOptions:animationOptions]; - }; - } - - [self insertSections:sections ofKind:ASDataControllerRowNodeKind atIndexSet:indexSet completion:completionBlock]; + [self insertSections:sections ofKind:ASDataControllerRowNodeKind atIndexSet:indexSet completion:^(NSArray *sections, NSIndexSet *indexSet) { + if (_delegateDidInsertSections) + [_delegate dataController:self didInsertSections:sections atIndexSet:indexSet withAnimationOptions:animationOptions]; + }]; } /** @@ -442,17 +361,17 @@ static void *kASSizingQueueContext = &kASSizingQueueContext; }]; } -- (void)reloadDataWithCompletion:(void (^)())completion +- (void)reloadDataWithAnimationOptions:(ASDataControllerAnimationOptions)animationOptions completion:(void (^)())completion { - [self _reloadDataSynchronously:NO completion:completion]; + [self _reloadDataWithAnimationOptions:animationOptions synchronously:NO completion:completion]; } -- (void)reloadDataImmediately +- (void)reloadDataImmediatelyWithAnimationOptions:(ASDataControllerAnimationOptions)animationOptions { - [self _reloadDataSynchronously:YES completion:nil]; + [self _reloadDataWithAnimationOptions:animationOptions synchronously:YES completion:nil]; } -- (void)_reloadDataSynchronously:(BOOL)synchronously completion:(void (^)())completion +- (void)_reloadDataWithAnimationOptions:(ASDataControllerAnimationOptions)animationOptions synchronously:(BOOL)synchronously completion:(void (^)())completion { [self performEditCommandWithBlock:^{ ASDisplayNodeAssertMainThread(); @@ -474,7 +393,12 @@ static void *kASSizingQueueContext = &kASSizingQueueContext; LOG(@"Edit Transaction - reloadData"); // Remove everything that existed before the reload, now that we're ready to insert replacements - [self deleteAllNodesOfKind:ASDataControllerRowNodeKind]; + NSArray *indexPaths = ASIndexPathsForMultidimensionalArray(_editingNodes[ASDataControllerRowNodeKind]); + [self _deleteNodesAtIndexPaths:indexPaths withAnimationOptions:animationOptions]; + + NSMutableArray *editingNodes = _editingNodes[ASDataControllerRowNodeKind]; + NSMutableIndexSet *indexSet = [[NSMutableIndexSet alloc] initWithIndexesInRange:NSMakeRange(0, editingNodes.count)]; + [self _deleteSectionsAtIndexSet:indexSet withAnimationOptions:animationOptions]; [self willReloadData]; @@ -484,19 +408,12 @@ static void *kASSizingQueueContext = &kASSizingQueueContext; [sections addObject:[[NSMutableArray alloc] init]]; } - [self _insertSections:sections atIndexSet:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, sectionCount)]]; + [self _insertSections:sections atIndexSet:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, sectionCount)] withAnimationOptions:animationOptions]; - [self _batchLayoutNodes:updatedNodes atIndexPaths:updatedIndexPaths]; + [self _batchLayoutNodes:updatedNodes atIndexPaths:updatedIndexPaths withAnimationOptions:animationOptions]; - if (_delegateDidReloadData || completion) { - [_mainSerialQueue performBlockOnMainThread:^{ - if (_delegateDidReloadData) { - [_delegate dataControllerDidReloadData:self]; - } - if (completion) { - completion(); - } - }]; + if (completion) { + dispatch_async(dispatch_get_main_queue(), completion); } }; diff --git a/AsyncDisplayKit/Details/ASRangeController.h b/AsyncDisplayKit/Details/ASRangeController.h index 61ee2470..74061f88 100644 --- a/AsyncDisplayKit/Details/ASRangeController.h +++ b/AsyncDisplayKit/Details/ASRangeController.h @@ -190,13 +190,6 @@ NS_ASSUME_NONNULL_BEGIN */ - (void)rangeController:(ASRangeController *)rangeController didDeleteSectionsAtIndexSet:(NSIndexSet *)indexSet withAnimationOptions:(ASDataControllerAnimationOptions)animationOptions; -/** - * Called for data reload. - * - * @param rangeController Sender. - */ -- (void)rangeControllerDidReloadData:(ASRangeController *)rangeController; - @end NS_ASSUME_NONNULL_END \ No newline at end of file diff --git a/AsyncDisplayKit/Details/ASRangeController.mm b/AsyncDisplayKit/Details/ASRangeController.mm index fa0610a0..0329ccfd 100644 --- a/AsyncDisplayKit/Details/ASRangeController.mm +++ b/AsyncDisplayKit/Details/ASRangeController.mm @@ -276,17 +276,4 @@ }); } -- (void)dataControllerDidReloadData:(ASDataController *)dataController -{ - ASPerformBlockOnMainThread(^{ - _rangeIsValid = NO; - - // When reload data we need to make sure that _rangeTypeIndexPaths is cleared as well, - // otherwise _updateVisibleNodeIndexPaths may try to retrieve nodes from dataSource that aren't there anymore - [_rangeTypeIndexPaths removeAllObjects]; - - [_delegate rangeControllerDidReloadData:self]; - }); -} - @end diff --git a/AsyncDisplayKit/Details/ASRangeControllerBeta.mm b/AsyncDisplayKit/Details/ASRangeControllerBeta.mm index 5239a8d8..e53000d9 100644 --- a/AsyncDisplayKit/Details/ASRangeControllerBeta.mm +++ b/AsyncDisplayKit/Details/ASRangeControllerBeta.mm @@ -267,12 +267,4 @@ }); } -- (void)dataControllerDidReloadData:(ASDataController *)dataController -{ - ASPerformBlockOnMainThread(^{ - _rangeIsValid = NO; - [_delegate rangeControllerDidReloadData:self]; - }); -} - @end