CollectionView + UIKit Dynamics在performBatchUpdates上崩溃:

Geo*_*oas 7 objective-c ios uicollectionview uicollectionviewlayout uikit-dynamics

我遇到了一个奇怪的崩溃并试图整天修复它.我有一个自定义UICollectionViewLayout,它基本上增加了细胞的重力和碰撞.

实施效果很好!当我尝试使用以下命令删除一个单元格时会出现问题:[self.collectionView performBatchUpdates:].

它给了我以下错误:

2013-12-12 21:15:35.269 APPNAME[97890:70b] *** Assertion failure in -[UICollectionViewData validateLayoutInRect:], /SourceCache/UIKit_Sim/UIKit-2935.58/UICollectionViewData.m:357

2013-12-12 20:55:49.739 APPNAME[97438:70b] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'UICollectionView recieved layout attributes for a cell with an index path that does not exist: <NSIndexPath: 0x975d290> {length = 2, path = 0 - 4}'
Run Code Online (Sandbox Code Playgroud)

我的模型处理正确,我可以看到它从中删除项目!

要删除的项的indexPaths正在对象之间正确传递.collectionView更新没有崩溃的唯一时间是我删除它上面的最后一个单元格,否则,崩溃就会发生.

这是我用来删除单元格的代码.

- (void)removeItemAtIndexPath:(NSIndexPath *)itemToRemove completion:(void (^)(void))completion
{
    UICollectionViewLayoutAttributes *attributes = [self.dynamicAnimator layoutAttributesForCellAtIndexPath:itemToRemove];

    [self.gravityBehaviour removeItem:attributes];
    [self.itemBehaviour removeItem:attributes];
    [self.collisionBehaviour removeItem:attributes];

    [self.collectionView performBatchUpdates:^{
        [self.fetchedBeacons removeObjectAtIndex:itemToRemove.row];
        [self.collectionView deleteItemsAtIndexPaths:@[itemToRemove]];
    } completion:nil];   
}
Run Code Online (Sandbox Code Playgroud)

处理单元属性的CollectionView委托是下面的基本委托.

- (CGSize)collectionViewContentSize
{
    return self.collectionView.bounds.size;
}

- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect
{
    return [self.dynamicAnimator itemsInRect:rect];
}

- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath
{
    return [self.dynamicAnimator layoutAttributesForCellAtIndexPath:indexPath];
}
Run Code Online (Sandbox Code Playgroud)

我已经尝试过的事情没有成功: - 使布局无效 - 重新加载数据 - 从UIDynamicAnimator中删除行为并在更新后再次添加它们

任何见解?

此存储库中提供了有问题的源代码.请检查一下.代码库

最好.乔治.

Geo*_*oas 12

经过几周的努力,这个bug,我们的朋友@ david-h和@erwin的一些有用的见解以及来自Apple的WWDR的一些电话和电子邮件,我能够解决这个问题.只想与社区分享解决方案.

  1. 问题.UIKit Dynamics有一些帮助方法来处理集合视图,这些方法实际上并没有做我认为应该自动执行的内部工作,比如在执行某些使用performBatchUpdates:的操作时自动更新动态动画单元格.所以你必须根据WWDR手动完成,所以我们迭代更新的itens更新他们的NSIndexPaths,这样动态动画师可以给我们正确的单元更新.

  2. 错误.即使对单元格插入/删除执行此indexPath更新,我也会在动画中出现大量随机崩溃和奇怪的行为.所以,我按照@erwin给出的一个提示,包括在performBatchUpdates之后重新实例化UIDynamicAnimator,并解决了这种情况下的所有问题.

所以代码.

- (void)removeItemAtIndexPath:(NSIndexPath *)itemToRemove completion:(void (^)(void))completion
{
    UICollectionViewLayoutAttributes *attributes = [self.dynamicAnimator layoutAttributesForCellAtIndexPath:itemToRemove];

    if (attributes) {
        [self.collisionBehaviour removeItem:attributes];
        [self.gravityBehaviour removeItem:attributes];
        [self.itemBehaviour removeItem:attributes];

        // Fix the problem explained on 1.
        // Update all the indexPaths of the remaining cells
        NSArray *remainingAttributes = self.collisionBehaviour.items;
        for (UICollectionViewLayoutAttributes *attributes in remainingAttributes) {
            if (attributes.indexPath.row > itemToRemove.row)
                attributes.indexPath = [NSIndexPath indexPathForRow:(attributes.indexPath.row - 1) inSection:attributes.indexPath.section];
        }

        [self.collectionView performBatchUpdates:^{
            completion();
            [self.collectionView deleteItemsAtIndexPaths:@[itemToRemove]];
        } completion:nil];

        // Fix the bug explained on 2.
        // Re-instantiate the Dynamic Animator
        self.dynamicAnimator = [[UIDynamicAnimator alloc] initWithCollectionViewLayout:self];
        [self.dynamicAnimator addBehavior:self.collisionBehaviour];
        [self.dynamicAnimator addBehavior:self.gravityBehaviour];
        [self.dynamicAnimator addBehavior:self.itemBehaviour];
    }
}
Run Code Online (Sandbox Code Playgroud)

我开了一个雷达解释了这个问题,希望Apple能够在未来的更新中解决这个问题.如果有人复制它,它可以在OpenRadar使用.

谢谢大家.