我正在研究通过Crashlytics使用 UICollectionView
崩溃的错误,该错误通常采用以下形式:
我相信这是因为我有一个collectionView,它会定期使用服务器中的数据刷新自身,并且服务器中的数据可能比客户端 UICollectionViewDataSource
中包含的项目更多或更少。
从服务器获取新数据时,我在集合 View 上调用reloadData
。
但是,由于在网络下载完成之前用户与我的收藏夹 View 的交互,有可能我之前已经调用了 reloadItemsAtIndexPaths
。 reloadItemsAtIndexPaths
在至少几百毫秒和许多处理器周期内似乎没有完成。因此,当在reloadItemsAtIndexPaths
中间更新dataSource时,将发生此崩溃。
是否有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
的同步。 最佳答案
就像您确定的那样,竞赛条件始终是复杂的问题。如果我对您的理解正确,那么您正在修改集合 View 的数据源,而它仍试图重新加载自身,这意味着解决方案是保留一个单独的数据存储,该存储将原子复制到集合 View 的数据源中。
所以:
这样一来,收集 View 就不必担心种族状况-它始终会从一组固定的数据中读取相关数据。