Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What's causing this iOS crash? UICollectionView received layout attributes for a cell with an index path that does not exist

I'm working on an app that has a UICollectionViewController that is crashing in certain mysterious situations that are hard to reproduce. The log for the crash looks like this:

*** Assertion failure in -[UICollectionViewData validateLayoutInRect:], /SourceCache/UIKit_Sim/UIKit-3318.16.14/UICollectionViewData.m:417 *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'UICollectionView received layout attributes for a cell with an index path that does not exist: <NSIndexPath: 0xc000000000008016> {length = 2, path = 0 - 1}' 

Crashes like this only seem to have started occurring in our code once we switched to the iOS 8 SDK.

Why is this happening?

Note: I already know what the answer to question is, but I found very little information relating to this crash on Stack Overflow and the rest of the web. I'll post the answer below. This bug took my coworker and I three days to track down, so hopefully this post will save someone else a lot of time and frustration. I have filed this bug with Apple.

like image 822
Drew Avatar asked Dec 16 '14 23:12

Drew


2 Answers

The crash was happening in the following situation:

We had a collection view controller that was presenting another view controller on top of it.

While the collection view controller was no longer visible, the following sequence of events was occasionally occurring in response to our app's back end requests.

  1. [UICollectionView insertItemsAtIndexPaths:] was called with 50 items on the collection view of the hidden UICollectionViewController.
  2. [UICollectionView reloadData] was called on the hidden collection view.
  3. A short delay would occur.
  4. The number of items in the hidden collection view was set to a small number.
  5. [UICollectionView reloadData] was called again.
  6. The view controller was dismissed, revealing the hidden collection view controller.

The assertion failure in the internal UIKit class UICollectionViewData would happen at step 6.

So, the lesson is, try to avoid manipulating a collection view that is not visible on the screen.

Our workaround for this problem was to call [UICollectionView reloadSections:] instead of [UICollectionView reloadData] at key points.

We suspect that the effects of reloadData are deferred to some point in the future, and there are consequently subtle issues with how this may interact with other method calls like insertItemsAtIndexPaths, whereas reloadSections is handled immediately, leaving the collection view in a better state.

We think that we were not seeing this behavior until we started building our app for iOS 8.

Sleep well, my friends!

like image 190
Drew Avatar answered Sep 21 '22 22:09

Drew


For me it was the UICollectionViewLayoutAttribute's array. I'm using it in a UICollectionViewLayout to store item's attribute.

I forgot to empty it in the prepareLayout method.

So the layoutAttributesForItemAtIndexPath was returning incorrect values for indexPath, which led to the same crash.

With just a removeAll on the array at the beginning of prepareLayout, it's working.

like image 37
Beuj Avatar answered Sep 22 '22 22:09

Beuj