When dragging to move cells in a UICollectionView, the app is crashing due to items being marked as invalidated, but then missing at the index path.
The code successfully confirms performs the move in the collection. Then the collection returns the expected number of sections and the cells for the section. After seemingly completing without issue, the following error occurs:
2018-12-20 15:39:54.216391-0500 TestApp[1748:485235] *** Assertion failure in -[UICollectionViewData invalidateItemsAtIndexPaths:], /BuildRoot/Library/Caches/com.apple.xbs/Sources/UIKitCore/UIKit-3698.93.8/UICollectionViewData.m:166
2018-12-20 15:39:54.216878-0500 TestApp[1748:485235] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'attempting to invalidate an item at an invalid indexPath: {length = 2, path = 0 - 1} globalIndex: 1 numItems: 0'
The code itself isn't doing anything very interesting. It makes sure that the last cell in edit mode (an add button) isn't moved, and then updates the data for our model.
It doesn't seem like any of the items in the collection should be invalidated in the first place. The number of items in the collection is fairly small, so everything is onscreen the entire time so no cells are being removed from view in this scenario. No content for any of the cells was changed, so I'm not entirely sure what could have been marked as invalid, but even with that occurring, I'm unaware why it would be missing.
Code below:
// MARK: UICollectionViewDataSource Functions
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
let friendsCount = AppDataModel.sharedInstance.groupModels[groupIndex!].friends.count
if friendsCount >= 0 {
return isEditingEnabled ? friendsCount + 1 : friendsCount
} else {
return 0
}
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if isEditingEnabled && indexPath.row == AppDataModel.sharedInstance.groupModels[groupIndex!].friends.count {
if !isUpgraded {
var currentVideoCount = 0
for i in 0..<AppDataModel.sharedInstance.groupModels.count {
currentVideoCount += AppDataModel.sharedInstance.groupModels[i].friends.count
}
if currentVideoCount >= maxFreeVideos {
print("Max Videos for trial reached.")
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "upgradeCell", for: indexPath)
return cell
}
}
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "addFriendCell", for: indexPath)
return cell
}
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "friendCell", for: indexPath) as! MainViewFriendCollectionViewCell
let friendForCell = AppDataModel.sharedInstance.groupModels[groupIndex!].friends[(indexPath as NSIndexPath).row]
cell.setup(friendForCell, shouldHideDeleteButton: !isEditingEnabled, onDeleteFriend: self.onDeleteFriend, onForceUpload: self.onForceUpload)
return cell
}
func collectionView(_ collectionView: UICollectionView, moveItemAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) {
// The user cannot reorder the add button
let addButtonIndex = AppDataModel.sharedInstance.groupModels[groupIndex!].friends.count
let destinationIndex = (destinationIndexPath.item >= addButtonIndex) ? addButtonIndex - 1 : (destinationIndexPath as NSIndexPath).item
// reflect the changes to the view in the model
AppDataModel.sharedInstance.groupModels[groupIndex!].updateFriendOrdersAfterReorder((sourceIndexPath as NSIndexPath).item, toIndex: destinationIndex)
}
func collectionView(_ collectionView: UICollectionView, targetIndexPathForMoveFromItemAt originalIndexPath: IndexPath, toProposedIndexPath proposedIndexPath: IndexPath) -> IndexPath {
let addButtonIndex = AppDataModel.sharedInstance.groupModels[groupIndex!].friends.count
return proposedIndexPath.item >= addButtonIndex ? originalIndexPath : proposedIndexPath
}