简体   繁体   English

防止UICollectionView崩溃

[英]Preventing crash in UICollectionView

Our app has UICollectionView and its dataSource dictionary is regularly updated. 我们的应用程序具有UICollectionView ,其dataSource字典定期更新。 We never know when next update will happen. 我们永远不知道下次更新何时会发生。 Collection View reload method could be called after user taps a button or it could happen asynchronous after network request success. 可以在用户点击按钮后调用Collection View重载方法,也可以在网络请求成功后异步进行。 Given above information we have the risk to have a race condition while reloading collection view and updating its data source at the same time. 鉴于上述信息,我们可能会在重新加载集合视图和同时更新其数据源时遇到竞争条件。 We even registered the following crash and we believe its happened because of the race condition described above. 我们甚至注册了下面的崩溃,我们认为它是因为上述竞争条件而发生的。 The crash message: 崩溃消息:

*** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArrayI objectAtIndex:]: index 1 beyond bounds [0 .. 0]'

The method which cause the crash: collectionViewLayout sizeForItemAtIndexPath: . 导致崩溃的方法: collectionViewLayout sizeForItemAtIndexPath: .

This method calculates height for collection View's section depending on items count in the sectionWithProducts . 此方法根据sectionWithProducts项目计数计算集合View的部分的sectionWithProducts It crashes because dataSource count is smaller than indexPath.row . 它崩溃是因为dataSource计数小于indexPath.row And the line causing the crash: 引起崩溃的线路:

NSArray *sectionWithProducts = self.dataSource[indexPath.row];

Following lines called before crash happened: 在发生崩溃之前调用以下行:

[self.collectionView setCollectionViewLayout:[self flowLayout] animated:NO];
[self.collectionView scrollRectToVisible:CGRectMake(0, 0, 1, 1) animated:NO];
[self.collectionView reloadData];

To prevent this we decided to put the only line of code which updates data source into main thread. 为了防止这种情况,我们决定将唯一一行更新数据源的代码放入主线程中。

// 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;
});

We had lots of [self.collectionView reloadData] in our code. 我们的代码中有很多[self.collectionView reloadData] Is it worth to run them on main thread as well? 是否值得在主线程上运行它们? It happened quickly so it shouldn't block UI for long. 它发生得很快,所以它不应该长时间阻止UI。

Is UICollectionViewDelegateFlowLayout delegate methods with indexPath property always called on background queue? 是否始终在后台队列上调用具有indexPath属性的UICollectionViewDelegateFlowLayout委托方法?

First of all, all UIKIT methods should be called on the main thread including reloadData. 首先,应该在主线程上调用所有UIKIT方法,包括reloadData。 This though won't solve your crash. 这虽然不能解决你的崩溃。 Secondly, somewhere in your code there is a race condition where you are calling reloadData and changing the data source simultaneously and you need to figure out where it is happening. 其次,在代码中的某个位置存在竞争条件,您正在调用reloadData并同时更改数据源,您需要确定它发生的位置。 This is what i can say without seeing the actual code. 这是我可以说的,没有看到实际的代码。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM