Iglistkit: Interactive cell reordering using ListCollectionViewLayout causes crash

Created on 22 May 2018  路  5Comments  路  Source: Instagram/IGListKit

New issue checklist

General information

  • IGListKit version: 3.4.0
  • iOS version(s): all versions
  • CocoaPods/Carthage version: 1.4.0
  • Xcode version: 9.3.1
  • Devices/Simulators affected: Both
  • Reproducible in the demo project? (Yes/No): Yes
  • Related issues: #976

Debug information

Hi,
I just found #976 (interactive reordering) and I'm trying to implement it into a project. However, instead of using UICollectionViewFlowLayout() I'd like to use ListCollectionViewLayout.

But with this layout, the app crashes when you try to reorder cells. If you open the IGListKit examples, go to ReorderableViewController.swift and change the layout to ListCollectionViewLayout(stickyHeaders: true, topContentInset: 0, stretchToEdge: true), it will crash with this message:

2018-05-22 15:25:00.631121+0200 IGListKitExamples[56979:3114758] * Assertion failure in -[UICollectionViewData validateLayoutInRect:], /BuildRoot/Library/Caches/com.apple.xbs/Sources/UIKit_Sim/UIKit-3698.52.10/UICollectionViewData.m:435
2018-05-22 15:25:00.648303+0200 IGListKitExamples[56979:3114758] *
Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'UICollectionView received layout attributes for a cell with an index path that does not exist: {length = 2, path = 5 - 0}'

Should this happen? Do I need to work with UICollectionViewFlowLayout? I'm not quite familiar with all of this, so maybe ListCollectionViewLayout isn't supposed to be working here.

Also, (this might be a related question, depending on how ListCollectionViewLayout works) : When the cells all have different heights (see code below, adjusting the section controller from the example), the dragged cell adjusts its own height depending on the cell beneath. This is pretty strange. But I don't know if using ListCollectionViewLayout() would fix this.

final class ReorderableSectionController: ListSectionController {

private var object: String?
var height: CGFloat!

override init() {
    super.init()
    // random height
    height = CGFloat(Int(arc4random_uniform(100)))
}

override func sizeForItem(at index: Int) -> CGSize {
    return CGSize(width: collectionContext!.containerSize.width, height: 30 + self.height)
}

....

Thanks for your help :)

bug

Most helpful comment

So I don't know if this is useful information or not but I found something that might cause the problem:

I subclassed the ListCollectionViewLayout and printed out the visible IndexPaths every time the layoutAttributesForElements(in:) method gets called:

class SubclassLayout: ListCollectionViewLayout {
        override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
        print(collectionView!.indexPathsForVisibleItems)
        return super.layoutAttributesForElements(in: rect)
    }
}

At the beginning it looks like this:

[[0, 0], [2, 0], [1, 0], [3, 0]]

(I have 4 objects in this example)

Right before it crashes (that's when I move the dragged cell over another cell), that's printed:

[[0, 1], [2, 0], [0, 0], [3, 0]]
(...) UICollectionView received layout attributes for a cell with an index path that does not exist: {length = 2, path = 0 - 0} (...)

It's path = 0 - 0 because I dragged the first cell. It would be path = 3 - 0 for the last cell and so on.

I think what happens here is that the system tries to append a section. It puts the object in another section and for that there are either no layout attributes or (as one section will be missing as a result) there are layout attributes for an IndexPath that thus does not exist.

I think that's the root cause of the problem. However, I'm not sure what to do with this information. Is there any possibility to prevent this?

All 5 comments

@delannoyk able to help here?

Sent with GitHawk

So I don't know if this is useful information or not but I found something that might cause the problem:

I subclassed the ListCollectionViewLayout and printed out the visible IndexPaths every time the layoutAttributesForElements(in:) method gets called:

class SubclassLayout: ListCollectionViewLayout {
        override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
        print(collectionView!.indexPathsForVisibleItems)
        return super.layoutAttributesForElements(in: rect)
    }
}

At the beginning it looks like this:

[[0, 0], [2, 0], [1, 0], [3, 0]]

(I have 4 objects in this example)

Right before it crashes (that's when I move the dragged cell over another cell), that's printed:

[[0, 1], [2, 0], [0, 0], [3, 0]]
(...) UICollectionView received layout attributes for a cell with an index path that does not exist: {length = 2, path = 0 - 0} (...)

It's path = 0 - 0 because I dragged the first cell. It would be path = 3 - 0 for the last cell and so on.

I think what happens here is that the system tries to append a section. It puts the object in another section and for that there are either no layout attributes or (as one section will be missing as a result) there are layout attributes for an IndexPath that thus does not exist.

I think that's the root cause of the problem. However, I'm not sure what to do with this information. Is there any possibility to prevent this?

Running into the same issue here as well.

@delannoyk Not sure if you're the right person but saw the earlier tag on this - any insight into whats going on here?

Whoopsie I didn't see the notification from the first time I was tagged, sorry about that 馃槓

@rnystrom @kmkarim I haven't worked on that feature but I can definitely try to help. I don't have any insight yet but I'll investigate and keep you posted.

@delannoyk Is there any updates on this issue? Hope the bug gets fixed soon.

Was this page helpful?
0 / 5 - 0 ratings