From 0830f6cf235f10e380bd3409b8c0d48ed855e439 Mon Sep 17 00:00:00 2001 From: Huy Nguyen Date: Tue, 15 May 2018 20:18:54 +0100 Subject: [PATCH] [ASCollectionNode/ASTableNode] Fix a crash occurs while remeasuring cell nodes (#917) --- CHANGELOG.md | 1 + Source/ASCollectionView.mm | 11 +++++++---- Source/ASTableView.mm | 14 +++++++------- Source/Details/ASDataController.h | 2 +- Source/Details/ASDataController.mm | 3 ++- 5 files changed, 18 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 127939ac55..2cdcc3f106 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -49,6 +49,7 @@ - Adds a check that Texture is compiled with stdc++11 as specified by the podfile. gnu++11 can cause subtle issues that are currently being investigated. [Adlai Holler](https://github.com/Adlai-Holler) - Adds an experiment to call ASNetworkImageNode callbacks off main. [Garrett Moon](https://github.com/garrettmoon) - Prevent UITextView from updating contentOffset while deallocating [Michael Schneider](https://github.com/maicki) +- [ASCollectionNode/ASTableNode] Fix a crash occurs while remeasuring cell nodes. [Huy Nguyen](https://github.com/nguyenhuy) [#917](https://github.com/TextureGroup/Texture/pull/917) ## 2.6 - [Xcode 9] Updated to require Xcode 9 (to fix warnings) [Garrett Moon](https://github.com/garrettmoon) diff --git a/Source/ASCollectionView.mm b/Source/ASCollectionView.mm index 72d8b78d41..b80da85571 100644 --- a/Source/ASCollectionView.mm +++ b/Source/ASCollectionView.mm @@ -1724,11 +1724,14 @@ static NSString * const kReuseIdentifier = @"_ASCollectionReuseIdentifier"; - (void)layoutSubviews { if (_cellsForLayoutUpdates.count > 0) { - NSMutableArray *nodesSizesChanged = [NSMutableArray array]; - [_dataController relayoutNodes:_cellsForLayoutUpdates nodesSizeChanged:nodesSizesChanged]; - [self nodesDidRelayout:nodesSizesChanged]; + NSArray *nodes = [_cellsForLayoutUpdates allObjects]; + [_cellsForLayoutUpdates removeAllObjects]; + + NSMutableArray *nodesSizeChanged = [NSMutableArray array]; + + [_dataController relayoutNodes:nodes nodesSizeChanged:nodesSizeChanged]; + [self nodesDidRelayout:nodesSizeChanged]; } - [_cellsForLayoutUpdates removeAllObjects]; // Flush any pending invalidation action if needed. ASCollectionViewInvalidationStyle invalidationStyle = _nextLayoutInvalidationStyle; diff --git a/Source/ASTableView.mm b/Source/ASTableView.mm index 58b3d033de..8a0e11a2ab 100644 --- a/Source/ASTableView.mm +++ b/Source/ASTableView.mm @@ -199,7 +199,6 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell"; // CountedSet because UIKit may display the same element in multiple cells e.g. during animations. NSCountedSet *_visibleElements; - BOOL _remeasuringCellNodes; NSHashTable *_cellsForLayoutUpdates; // See documentation on same property in ASCollectionView @@ -745,26 +744,27 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell"; - (void)layoutSubviews { // Remeasure all rows if our row width has changed. - _remeasuringCellNodes = YES; UIEdgeInsets contentInset = self.contentInset; CGFloat constrainedWidth = self.bounds.size.width - [self sectionIndexWidth] - contentInset.left - contentInset.right; if (constrainedWidth > 0 && _nodesConstrainedWidth != constrainedWidth) { _nodesConstrainedWidth = constrainedWidth; + [_cellsForLayoutUpdates removeAllObjects]; [self beginUpdates]; [_dataController relayoutAllNodesWithInvalidationBlock:nil]; [self endUpdatesAnimated:(ASDisplayNodeLayerHasAnimations(self.layer) == NO) completion:nil]; } else { if (_cellsForLayoutUpdates.count > 0) { - NSMutableArray *nodesSizesChanged = [NSMutableArray array]; - [_dataController relayoutNodes:_cellsForLayoutUpdates nodesSizeChanged:nodesSizesChanged]; - if (nodesSizesChanged.count > 0) { + NSArray *nodes = [_cellsForLayoutUpdates allObjects]; + [_cellsForLayoutUpdates removeAllObjects]; + + NSMutableArray *nodesSizeChanged = [NSMutableArray array]; + [_dataController relayoutNodes:nodes nodesSizeChanged:nodesSizeChanged]; + if (nodesSizeChanged.count > 0) { [self requeryNodeHeights]; } } } - [_cellsForLayoutUpdates removeAllObjects]; - _remeasuringCellNodes = NO; // To ensure _nodesConstrainedWidth is up-to-date for every usage, this call to super must be done last [super layoutSubviews]; diff --git a/Source/Details/ASDataController.h b/Source/Details/ASDataController.h index 8792637ba1..02952c0c59 100644 --- a/Source/Details/ASDataController.h +++ b/Source/Details/ASDataController.h @@ -255,7 +255,7 @@ extern NSString * const ASCollectionInvalidUpdateException; * * @discussion Used to respond to setNeedsLayout calls in ASCellNode */ -- (void)relayoutNodes:(id)nodes nodesSizeChanged:(NSMutableArray * _Nonnull)nodesSizesChanged; +- (void)relayoutNodes:(id)nodes nodesSizeChanged:(NSMutableArray *)nodesSizesChanged; /** * See ASCollectionNode.h for full documentation of these methods. diff --git a/Source/Details/ASDataController.mm b/Source/Details/ASDataController.mm index 8779047694..f48c8dfc71 100644 --- a/Source/Details/ASDataController.mm +++ b/Source/Details/ASDataController.mm @@ -779,8 +779,9 @@ typedef void (^ASDataControllerSynchronizationBlock)(); #pragma mark - Relayout -- (void)relayoutNodes:(id)nodes nodesSizeChanged:(NSMutableArray *)nodesSizesChanged +- (void)relayoutNodes:(id)nodes nodesSizeChanged:(NSMutableArray *)nodesSizesChanged { + NSParameterAssert(nodes); NSParameterAssert(nodesSizesChanged); ASDisplayNodeAssertMainThread();