Удалить элемент из CollectionView с разделами iOS Swift - PullRequest
0 голосов
/ 05 ноября 2018

У меня есть CollectionView с разделами (2 раздела). Когда я удаляю ячейку из раздела 1, ее удаление очень хорошее. Но когда я удаляю ячейку из раздела 0, мое приложение вылетает с ошибкой, подобной этой:

недопустимое количество элементов в разделе 0. Количество элементов, содержащихся в существующем разделе после обновления (5), должно быть равно количеству элементов, содержащихся в этом разделе до обновления (5), плюс или минус число элементов, вставленных или удаленных из этого раздела (0 вставлено, 1 удалено) и плюс или минус количество элементов, перемещенных в или из этого раздела (0 перемещено, 0 перемещено). с userInfo (null)

Прежде чем удалить элемент из collectionView, я удаляю его из моего источника данных в executeBatchUpdates:

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 - функция, которая нарезает массив следующим образом (5 элементов в разделе):

До порции:

[1,2,3,4,5,6,7,8,9,10]

После порции:

[
    [1, 2, 3, 4, 5], // first section in collectionView
    [6, 7, 8, 9, 10], // second section in collectionView
] 

Я заполняю свои элементы из Базовых данных в collectionView с помощью следующих функций:

    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
    }
}

Элемент удаляется из collectionView и CoreData, когда пользователь долго нажимает на этот элемент (ячейку). Процесс удаления здесь:

@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)
        }
    }
}

Изображение этого процесса: введите описание изображения здесь

Мой проект похож на приложение Apple Books. Я хочу повторить процесс удаления книги ...

Мой полный код здесь (GitHub). Плис, используйте iPhone SE симулятор. Мои данные в файле items.plist и автоматическое сохранение в CoreData при первом запуске приложения.

Где в моем коде ошибка?

Ответы [ 2 ]

0 голосов
/ 05 ноября 2018

Возможно, проблема в том, что вы удаляете один элемент раздела 0, а после удаления раздел 0 все еще с тем же числом итэнов перед удалением, потому что вы «перераспределяете» итены после каждого удаления.

0 голосов
/ 05 ноября 2018

Когда вы удаляете из CollectionView, вы должны также удалить из базового массива данных (items2).

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)

        for indexPath in self.deletedItemIndex! {
           items2[indexPath.section].remove(at: indexPath.row)
        }
        self.collectionView?.deleteItems(at: [self.deletedItemIndex!])
    })
}
...