I have a CollectionView with sections (2 sections). When I delete a cell from section 1 its deleting very good. But when I delete a cell from section 0 my app is crashing with error like this:
invalid number of items in section 0. The number of items contained in an existing section after the update (5) must be equal to the number of items contained in that section before the update (5), plus or minus the number of items inserted or deleted from that section (0 inserted, 1 deleted) and plus or minus the number of items moved into or out of that section (0 moved in, 0 moved out). with userInfo (null)
Before delete item from collectionView, I delete it item from my data source in performBatchUpdates:
extension MainCollectionViewController: NSFetchedResultsControllerDelegate {
func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
collectionView?.performBatchUpdates({ [weak self] in
guard let self = self else { return }
items = controller.fetchedObjects as! [Item]
items2 = items.chunked(into: 5)
self.collectionView?.deleteItems(at: [self.deletedItemIndex!])
})
}
}
extension Array {
func chunked(into size: Int) -> [[Element]] {
return stride(from: 0, to: count, by: size).map {
Array(self[$0 ..< Swift.min($0 + size, count)])
}
}
}
func chunked - is a function that slice array like this (5 items in section):
Before chunked:
[1,2,3,4,5,6,7,8,9,10]
After chunked:
[
[1, 2, 3, 4, 5], // first section in collectionView
[6, 7, 8, 9, 10], // second section in collectionView
]
I populate my items from Core Data to collectionView with this functions:
override func numberOfSections(in collectionView: UICollectionView) -> Int {
print("call numberOfSections")
//3
return items2.count
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
print("call numberOfItemsInSection, current section is \(section)")
//4
return items2[section].count
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! CollectionViewCell
let item = items2[indexPath.section][indexPath.row]
cell.itemNameTextLabel.text = item.name
cell.itemImageView.image = UIImage(data: item.image! as Data)
return cell
}
}
Item deleting from collectionView and CoreData when user long press it item (cell). Deleting process is here:
@objc func handleLongPress(gesture: UILongPressGestureRecognizer!) {
if gesture.state != .ended {
return
}
let p = gesture.location(in: self.collectionView)
if let indexPath = self.collectionView?.indexPathForItem(at: p) {
let fetchRequest: NSFetchRequest<Item> = Item.fetchRequest()
fetchRequest.predicate = NSPredicate(format: "name == %@", self.items2[indexPath.section][indexPath.row].name!)
do {
if let context = (UIApplication.shared.delegate as? AppDelegate)?.persistentContainer.viewContext {
let selectedItem = try context.fetch(fetchRequest)[0]
//save deleted item index in var that use it index in performBatchUpdatesBlock
deletedItemIndex = IndexPath(row: indexPath.row, section: indexPath.section)
context.delete(selectedItem)
do {
try context.save()
print("Save!")
} catch let error as NSError {
print("Oh, error! \(error), \(error.userInfo)")
}
}
} catch {
print(error.localizedDescription)
}
}
}
Image of this process: enter image description here
My project like Apple Books app. I want to repeat deleting book process...
My full code is here (GitHub). Plis, use iPhone SE simulator. My data in items.plist file and automatic saving to CoreData when run app in first time.
Where is mistake in my code?