Ignore Relayout Requests for Deleted Cell Nodes (#279)

* Data Controller: Ignore relayout requests for elements that have been deleted in the mean-time.

* Bolster our logchange

* Add sanity check
This commit is contained in:
Adlai Holler
2017-05-16 11:31:15 -07:00
committed by GitHub
parent e6accc7ea6
commit 432018cfdc
5 changed files with 24 additions and 5 deletions

View File

@@ -22,3 +22,4 @@
- [ASVideoNode] Added error reporing to ASVideoNode and it's delegate [#260](https://github.com/TextureGroup/Texture/pull/260)
- [ASCollectionNode] Fixed conversion of item index paths between node & view. [Adlai Holler](https://github.com/Adlai-Holler) [#262](https://github.com/TextureGroup/Texture/pull/262)
- [Layout] Extract layout implementation code into it's own subcategories [Michael Schneider] (https://github.com/maicki)[#272](https://github.com/TextureGroup/Texture/pull/272)
- [Fix] Fix a potential crash when cell nodes that need layout are deleted during the same runloop. [Adlai Holler](https://github.com/Adlai-Holler) [#279](https://github.com/TextureGroup/Texture/pull/279)

View File

@@ -1664,9 +1664,12 @@ static NSString * const kReuseIdentifier = @"_ASCollectionReuseIdentifier";
- (BOOL)dataController:(ASDataController *)dataController presentedSizeForElement:(ASCollectionElement *)element matchesSize:(CGSize)size
{
NSIndexPath *indexPath = [self indexPathForNode:element.node];
if (indexPath == nil) {
ASDisplayNodeFailAssert(@"Data controller should not ask for presented size for element that is not presented.");
return YES;
}
UICollectionViewLayoutAttributes *attributes = [self layoutAttributesForItemAtIndexPath:indexPath];
CGRect rect = attributes.frame;
return CGSizeEqualToSizeWithIn(rect.size, size, FLT_EPSILON);
return CGSizeEqualToSizeWithIn(attributes.size, size, FLT_EPSILON);
}

View File

@@ -1750,6 +1750,10 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell";
- (BOOL)dataController:(ASDataController *)dataController presentedSizeForElement:(ASCollectionElement *)element matchesSize:(CGSize)size
{
NSIndexPath *indexPath = [self indexPathForNode:element.node];
if (indexPath == nil) {
ASDisplayNodeFailAssert(@"Data controller should not ask for presented size for element that is not presented.");
return YES;
}
CGRect rect = [self rectForRowAtIndexPath:indexPath];
/**

View File

@@ -71,7 +71,8 @@ extern NSString * const ASCollectionInvalidUpdateException;
- (NSUInteger)numberOfSectionsInDataController:(ASDataController *)dataController;
/**
Returns if the collection element size matches a given size
Returns if the collection element size matches a given size.
@precondition The element is present in the data controller's visible map.
*/
- (BOOL)dataController:(ASDataController *)dataController presentedSizeForElement:(ASCollectionElement *)element matchesSize:(CGSize)size;

View File

@@ -717,10 +717,20 @@ typedef void (^ASDataControllerCompletionBlock)(NSArray<ASCollectionElement *> *
}
id<ASDataControllerSource> dataSource = self.dataSource;
auto visibleMap = self.visibleMap;
auto pendingMap = self.pendingMap;
for (ASCellNode *node in nodes) {
ASSizeRange constrainedSize = [self constrainedSizeForElement:node.collectionElement inElementMap:_pendingMap];
auto element = node.collectionElement;
// Ensure the element is present in both maps or skip it. If it's not in the visible map,
// then we can't check the presented size. If it's not in the pending map, we can't get the constrained size.
// This will only happen if the element has been deleted, so the specifics of this behavior aren't important.
if ([visibleMap indexPathForElement:element] == nil || [pendingMap indexPathForElement:element] == nil) {
continue;
}
ASSizeRange constrainedSize = [self constrainedSizeForElement:element inElementMap:pendingMap];
[self _layoutNode:node withConstrainedSize:constrainedSize];
BOOL matchesSize = [dataSource dataController:self presentedSizeForElement:node.collectionElement matchesSize:node.frame.size];
BOOL matchesSize = [dataSource dataController:self presentedSizeForElement:element matchesSize:node.frame.size];
if (! matchesSize) {
[nodesSizesChanged addObject:node];
}