ios - 如果数据源计数可能发生变化,是否可以同时使用 reloadItemsAtIndexPaths 和 reloadData?

标签 ios objective-c uicollectionview

我正在调查一个崩溃错误 UICollectionView通过通常采用这种形式的 Crashlytics:

Fatal Exception: NSInternalInconsistencyException Invalid update: invalid number of items in section 0. The number of items contained in an existing section after the update (25) must be equal to the number of items contained in that section before the update (27), plus or minus the number of items inserted or deleted from that section (1 inserted, 1 deleted) and plus or minus the number of items moved into or out of that section (0 moved in, 0 moved out).

我认为这是因为我有一个 collectionView 会定期使用来自服务器的数据刷新自身,并且来自服务器的数据可能比客户端包含的项目更多或更少 UICollectionViewDataSource .

当我从服务器获取新数据时,我在我的集​​合 View 上调用 reloadData

但是,有可能是由于用户在网络下载完成之前与我的收藏 View 进行了交互,我调用了 reloadItemsAtIndexPaths就在之前。 reloadItemsAtIndexPaths 至少在几百毫秒和许多处理器周期内似乎没有完成。因此,当 dataSource 在 reloadItemsAtIndexPaths 的中间更新时,会发生此崩溃。

reloadItemsAtIndexPaths 是否有“立即”形式?或者我必须一直调用 reloadData鉴于我的用例,它似乎确实会立即更新所有内容并在最后使 UICollectionView 保持良好状态。


编辑

根据 TwoStraws 的建议,这是我所做的:

    // Prevent data source from batch updating while we work
    self.dataSource.locked = YES;

    [self.collectionView performBatchUpdates:^{
        [self.collectionView reloadItemsAtIndexPaths:@[indexPath]];
    } completion:^(BOOL finished) {
        self.dataSource.locked = NO;
    }];

然后在我的数据源类中,从服务器收到结果后,我总是调用 assignResults:

- (void)assignResults:(NSMutableArray *)newResults {
    if (!self.locked) {
        self.results = newResults;
        [self.delegate handleDataSourceUpdated:self];
    } else {
        self.pendingResults = newResults;
    }
}

- (void)setLocked:(BOOL)locked {
    _locked = locked;

    if (!locked && self.pendingResults) {
        [self assignResults:self.pendingResults];
        self.pendingResults = nil;
    }
}

如您所见,只有在数据源未锁定时才会分配结果;否则,它们会在数据源被 UICollectionViewController 解锁时分配。请注意,所有这些方法都发生在主线程上,因此我无需担心我的 bool 属性 locked 的同步问题。

最佳答案

竞态条件总是很复杂的问题,我相信你知道。如果我理解正确的话,你正在修改 Collection View 的数据源,而它仍在尝试重新加载自身,这意味着解决方案是保留一个单独的数据存储,该数据存储以原子方式复制到 Collection View 的数据源。

所以:

  • Collection View 从数据源 A 读取数据。
  • 网络写入数据源 B。
  • 在您指定的位置,一口气将 B 复制到 A。
  • 告诉 Collection View 重新加载。

这样一来, Collection View 就永远不必担心竞态条件——它总是从它所关注的固定数据集中读取数据。

关于ios - 如果数据源计数可能发生变化,是否可以同时使用 reloadItemsAtIndexPaths 和 reloadData?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34209183/

相关文章:

ios - 为什么它会覆盖数据而不是在 firebase 中添加更多数据?

objective-c - 比较 switch 语句中的数字

ios - UITableViewCell 调整大小不流畅

ios - swift:CollectionView 单元格大小

iphone - 无法在 iphone 中使用 Sharekit 共享链接

ios - UICollectionView 单元仅在第二次调用 reloadData 后显示

iphone - 为 UITableViewCell 的飞行设置动画

ios - 在 Xcode 中收到 "Check dependencies warning: skipping file"错误

iphone - 如何在 UIToolBar 中添加条形按钮

ios - Switch 语句嵌套格式 - 哪个是正确的?