如何优雅地从UICollectionView performBatchUpdates:的断言失败中恢复

3

我有一个UICollectionView,它会像这样进行更新:

[self.collectionView performBatchUpdates:^{
    [self.collectionView deleteItemsAtIndexPaths:pathsRemoved];
    [self.collectionView insertItemsAtIndexPaths:pathsAdded];
}

通常情况下,这样做效果很好,但在某些情况下,数据源计数与原始项目数量(pathsRemoved的计数+pathsAdded的计数)不匹配。
因此,我将此代码包装在@try/@catch块中,然后调用[self.collectionView reloadData]。
然而,重新加载数据后,布局会变得混乱;以前存在的单元格(屏幕上方的单元格,但不在屏幕上)不再显示。集合视图的内容大小是正确的,我可以上下滚动,但只能看到重新加载时屏幕上的单元格。
有趣的是,Reveal.app显示其他单元格实际上存在,但被隐藏了。我有一个预感,这是一个误导,这里正在进行一些视图缓存,但这些单元格仍然在Reveal中列出。
我尝试过无效化布局、调用layoutIfNeeded以及我找到的各种子类流布局技巧,但什么都没有解决。
我不得不通过做自己的良性断言来减轻这个问题,并检查计数是否相加。如果它们相加,就执行performBatchUpdates。否则,不要费事,只需重新加载。这个方法有效,因为我们完全绕过了performBatchUpdates:但我必须问:
从performBatchUpdates:中优雅地恢复断言异常的更好方法是什么?还是说UICollectionView仍然有缺陷(在iOS 7上仍然存在)?

1
一般而言,在Cocoa中,如果你被迫捕捉异常,那就错了™。更好的解决方案是修复插入/删除代码中的潜在问题。某种方式上,你的数据源与集合视图不同步。我建议阅读“CollectionView编程指南”中的“插入、删除和移动部分和项”以了解确切的语义:https://developer.apple.com/library/ios/documentation/WindowsViews/Conceptual/CollectionViewPGforIOS/CreatingCellsandViews/CreatingCellsandViews.html#//apple_ref/doc/uid/TP40012334-CH7-SW7 - David Cairns
1个回答

3

我找到了一个处理这个问题的方法!

我试图像你一样把performBatchUpdates:的代码放在@try/@catch块中,并调用[collectionView reloadData]。

然后我意识到,当我的ViewController被释放时,collectionView也消失了,问题也消失了。

所以我找到了一个丑陋但有效的解决方案:在catch块中杀死旧的collectionView并创建一个新的。

@try {
    [collectionView performBatchUpdates:^ {
        // Do your stuff
    }];

}
@catch (NSException *exception) {
    UIView *oldSuperview = self.collectionView.superview;

    [self.collectionView removeFromSuperview];

    self.collectionView = [[UICollectionView alloc] initWithFrame:self.collectionView.frame collectionViewLayout:self.collectionView.collectionViewLayout];

    self.collectionView.dataSource = self;
    self.collectionView.delegate = self;
    // set other collectionView's properties here

    [oldSuperview addSubview:self.collectionView];
}

我知道这不好,但它救了我!

1
你已经想出如何在Swift中实现这个了吗?我用do-catch无法让它工作。 - 3lvis

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接