【发布时间】:2015-04-30 12:53:06
【问题描述】:
我们的应用程序有UICollectionView,其dataSource 字典会定期更新。我们永远不知道下一次更新何时发生。 Collection View reload 方法可以在用户点击按钮后调用,也可以在网络请求成功后异步发生。鉴于上述信息,我们有可能在重新加载集合视图并同时更新其数据源时出现竞争条件。我们甚至记录了以下崩溃,我们相信它的发生是由于上述竞争条件。崩溃消息:
*** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArrayI objectAtIndex:]: index 1 beyond bounds [0 .. 0]'
导致崩溃的方法:collectionViewLayout sizeForItemAtIndexPath:.
此方法根据sectionWithProducts 中的项目数计算集合视图部分的高度。它崩溃是因为dataSource 计数小于indexPath.row。导致崩溃的行:
NSArray *sectionWithProducts = self.dataSource[indexPath.row];
崩溃发生前调用的以下行:
[self.collectionView setCollectionViewLayout:[self flowLayout] animated:NO];
[self.collectionView scrollRectToVisible:CGRectMake(0, 0, 1, 1) animated:NO];
[self.collectionView reloadData];
为了防止这种情况,我们决定将更新数据源的唯一代码行放入主线程。
// Always run on main thread in hope to prevent NSRangeException.
// Reloading data should happen only sequential.
dispatch_async(dispatch_get_main_queue(), ^(void) {
self.dataSource = newValue;
});
我们的代码中有很多[self.collectionView reloadData]。是否值得在主线程上运行它们?它发生得很快,所以它不应该长时间阻塞 UI。
是否总是在后台队列上调用具有indexPath 属性的UICollectionViewDelegateFlowLayout 委托方法?
【问题讨论】:
标签: ios uikit uicollectionview