如何从 UICollectionView 中正确删除单元格?

Posted

技术标签:

【中文标题】如何从 UICollectionView 中正确删除单元格?【英文标题】:How to correctly delete a cell from 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。 【参考方案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])
            
        
    

【讨论】:

以上是关于如何从 UICollectionView 中正确删除单元格?的主要内容,如果未能解决你的问题,请参考以下文章

从 Storyboard 加载的 UICollectionView 未正确调整大小

UITableViewCell 中的 UICollectionView 如何设置选择以将数据从当前视图传递到另一个视图

如何在使用自定义单元格的 UICollectionView 中正确设置异步图像下载?

UICollectionView 方向改变事故?

在 UICollectionView 中重新加载数据的正确方法是啥?

UICollectionView 委托方法没有被正确调用