Search code examples
iosobjective-cios11

Terminating app due to uncaught exception 'NSRangeException' when calling dequeueReusableCellWithReuseIdentifier:forIndexPath:


We've run into a crash and all we can see is these from the crashlog:

2018-11-02 10:15:01.744674-0400 Flights[385:17563] *** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArrayM objectAtIndexedSubscript:]: index 0 beyond bounds for empty array'
*** First throw call stack:
(0x18555ed8c 0x1847185ec 0x1854f7750 0x1854e48ac 0x18f266b04 0x18f266084 0x18f265fd8 0x18f265eb8 0x18f2859dc 0x18f286c00 0x18f286a2c 0x100b1c304 0x100ea8b6c 0x100eaa24c 0x100eaa30c 0x100eaa680 0x185566580 0x185445748 0x18544a56c 0x10573e0c8 0x1855642d4 0x18544a41c 0x18f266f60 0x18f266084 0x18f265fd8 0x18f265eb8 0x18f265500 0x18f264730 0x18f133770 0x1896d525c 0x1896d93ec 0x189645aa0 0x18966d5d0 0x18966e450 0x185506910 0x185504238 0x185504884 0x185424da8 0x187407020 0x18f40578c 0x100b8c760 0x184eb5fc0)
libc++abi.dylib: terminating with uncaught exception of type NSException

We've enabled the all exceptions breakpoints and it points us to this line of code:

UICollectionViewCell* cell = [collectionView dequeueReusableCellWithReuseIdentifier:reuseIdentifier forIndexPath:path];

One thing that is very weird is that we can only reproduce this in iOS 11.3 devices. But all our other test devices work fine.

We are pretty much stuck. Anybody runs into this before and knows any workaround?


Solution

  • Not sure if it is a bug in iOS 11 or not, but the crash is cost by the following code of trying to dequeue a cell for sizing purposes in collectionView:collectionViewLayout:sizeForItemAt: and works fine on iOS 12 and above:

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        let cell = self.collectionView(collectionView, cellForItemAt: indexPath)
        let size = cell.systemLayoutSizeFitting(...)
        return CGSize(width: collectionView.frame.width, height: size.height)
    }
    

    And we are loading the nib with bundle parameter being nil as the following.

    let nib = UINib(nibName: "MyCell", bundle: nil)
    collectionView.register(nib, forCellWithReuseIdentifier: "MyCell")
    

    That for some reason gives us the obscure exception:

    2018-11-02 10:15:01.744674-0400 Flights[385:17563] *** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArrayM objectAtIndexedSubscript:]: index 0 beyond bounds for empty array'
    *** First throw call stack:
    (0x18555ed8c 0x1847185ec 0x1854f7750 0x1854e48ac 0x18f266b04 0x18f266084 0x18f265fd8 0x18f265eb8 0x18f2859dc 0x18f286c00 0x18f286a2c 0x100b1c304 0x100ea8b6c 0x100eaa24c 0x100eaa30c 0x100eaa680 0x185566580 0x185445748 0x18544a56c 0x10573e0c8 0x1855642d4 0x18544a41c 0x18f266f60 0x18f266084 0x18f265fd8 0x18f265eb8 0x18f265500 0x18f264730 0x18f133770 0x1896d525c 0x1896d93ec 0x189645aa0 0x18966d5d0 0x18966e450 0x185506910 0x185504238 0x185504884 0x185424da8 0x187407020 0x18f40578c 0x100b8c760 0x184eb5fc0)
    libc++abi.dylib: terminating with uncaught exception of type NSException
    

    However, changing the bundle parameter being .main (thanks to the comments) like the following give us a more appropriate crash log and call stack.

    let nib = UINib(nibName: "MyCell", bundle: .main)
    

    That leads us to the actual solution to the problem: do not call collectionView(collectionView, cellForItemAt: indexPath) during layout.