【问题标题】:How to correctly delete a cell from UICollectionView?如何从 UICollectionView 中正确删除单元格?
【发布时间】:2019-04-15 13:51:22
【问题描述】:

我正在尝试从 UICollectionView 中删除单元格,但出现“无效更新”错误

'无效更新:第0节中的项目数无效。更新后现有节中包含的项目数(9)必须等于更新前该节中包含的项目数(9),加上或减去从该部分插入或删除的项目数(0 插入,1 个删除),加上或减去移入或移出该部分的项目数(0 移入,0 移出)。'

我尝试在从 CollectionView 中删除项目之前更新我的 DataModel,但没有成功。

这是我的代码:

func didChangeQunatityOfCartProductAt(index: IndexPath?, product: ItemsModel?) {
    if let quantity =  product?.quantity{
        if let indexPath = index{
            if quantity == 0{
                self.products.remove(at: indexPath.row)
                self.collectionView.deleteItems(at: [indexPath])
            }
        }
    }
}

这是我的 numberOfItemsInSection 函数:

 func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
    return products.count
}

即使我在网上找到的所有解决方案都是相同的,但我仍然得到相同的结果。

【问题讨论】:

  • 在主线程上做所有事情,也许......?
  • 你能分享你在 collectionView:numberOfItemsInSection 中的代码吗?
  • @JonRose 请查看更新后的问题
  • 在 self.products.remove(at: indexPath.row) 行之后检查产品数组。数据是否已成功从产品中移除?
  • 看看 WWDC 会议A Tour of UICollectionView。他们描述了如何正确更新模型和集合视图。幻灯片 50 - 62。

标签: ios swift uicollectionview


【解决方案1】:

你应该试试collectionview的performBatchUpdates(_:completion:)

func didChangeQunatityOfCartProductAt(index: IndexPath?, product: ItemsModel?) {
    if let quantity =  product?.quantity {
        if let indexPath = index {
            if quantity == 0 {
                self.products.remove(at: indexPath.row)
                self.collectionView.performBatchUpdates({
                   self.collectionView.deleteItems(at: [indexPath])
                }){
                   // optional closure
                  }
            }
        }
    }
}

【讨论】:

    【解决方案2】:

    我发现了问题,我在删除索引处的项目后自动重新加载集合视图,其中 products 数组在类的顶部有一个属性观察器,它重新加载集合视图,并且在删除它之后修复了问题

    【讨论】:

      【解决方案3】:

      您可以尝试从 dataSource 数组中删除数据并调用 reloadData 方法来“刷新”您的 collectionViewDatasource

      func didChangeQunatityOfCartProductAt(index: IndexPath?, product: ItemsModel?) {
          if let quantity =  product?.quantity {
              if let indexPath = index {
                  if quantity == 0 {
                      self.products.remove(at: indexPath.row)
                      self.collectionView.reloadData()
                  }
              }
          }
      }
      

      这里唯一的区别是将单元格删除替换为:

      self.collectionView.reloadData()
      

      【讨论】:

      • reloadData() 导致 collectionView 一直滚动到屏幕顶部,这不好
      【解决方案4】:

      您应该从 array(Products) 中删除 indexPath.item,因为它是 indexPath.row 的集合视图。

      func didChangeQunatityOfCartProductAt(index: IndexPath?, product: ItemsModel?) {
          if let quantity =  product?.quantity{
              if let indexPath = index {
                  if quantity == 0 {
                      DispatchQueue.global(qos: .userInteractive).async { [weak self] in
                          self.products.remove(at: indexPath.item)
                          DispatchQueue.main.async { [weak self] in
                              self?.collectionView.deleteItems(at: [indexPath])
                              self?.collectionView.reloadData() // or you can reload the specific indexPath
                          }
                  }
              }
          }
      }
      

      【讨论】:

      • 我试过之后还是有同样的问题
      【解决方案5】:

      如果您的产品数量为 0,您如何删除产品? 您应该从该代码中删除 self.products.remove,因为该产品不再存在。

      func didChangeQunatityOfCartProductAt(index: IndexPath?, product: ItemsModel?) {
          if let quantity =  product?.quantity{
              if let indexPath = index{
                  if quantity == 0{
                      self.collectionView.deleteItems(at: [indexPath])
                  }
              }
          }
      }
      

      【讨论】: