尝试删除多个(以编程方式添加的)单元格后 CollectionView 崩溃

CollectionView crashing after I try deleting multiple (programmatically added) cells

我有一个带有非常简单数据源的 UICollectionView。它只是一个以编程方式更新的字符串数组。使用此 UICollectionView,我可以点击 select 多个单元格 - 然后可以使用删除按钮删除所有 selected 单元格。很简单,除了我有时会遇到致命错误:索引超出范围。

通过在另一个名为 "All Hobbies" 的集合视图中点击单元格以编程方式添加单元格 - 在 "All Hobbies" CV 中点击和 select 的任何单元格都会添加到 "My Hobbies." 我通过将点击的单元格的值附加到控制 My Hobbies CV 的数组来做到这一点。

问题

  1. 根据我 select 在我的爱好中的哪些单元格,删除按钮(下面的代码)有时会删除它们,或者有时会崩溃并出现致命错误:索引超出范围。它似乎不会在第一次删除时崩溃(如果有帮助的话。)
  2. 如果我的爱好中的单元格确实删除了,当我点击 "All Hobbies" 中的更多单元格时 - 它们添加到 "My Hobbies" 为 UIColor.red(表示它们是 selected。)(然后在我按下 delete btn 后会迟到崩溃。)单元格应添加为黄色。

我的数据似乎在删除后没有更新,当我再次尝试删除时,索引超出了范围。但是我在我的代码中找不到导致这种情况发生的问题(如果这确实是问题...)

Class 等级

let allHobbiesArray = ["Skiing", "Jogging", "Bicycling", "Basketball", "Cricket", "Being a Couch Potato", "Skiing", "Jogging", "Bicycling", "Basketball", "Cricket", "Being a Couch Potato", "Skiing", "Jogging", "Bicycling", "Basketball", "Cricket", "Being a Couch Potato", "Skiing", "Jogging", "Bicycling", "Basketball", "Cricket", "Being a Couch Potato"]
var myHobbiesArray = [String]()
var allSelected = [IndexPath]()

数据源

func numberOfSections(in collectionView: UICollectionView) -> Int {
    return 1
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    if collectionView == allHobbiesCV {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "ALL", for: indexPath) as! AllHobbiesCell
        cell.allHobbiesLabel.text = allHobbiesArray[indexPath.row]
        return cell
    }
    else {
        let cell = myHobbiesCV.dequeueReusableCell(withReuseIdentifier: "MY", for: indexPath) as! MyHobbiesCell
        cell.myHobbiesLabel.text = myHobbiesArray[indexPath.row]
        return cell
    }
}

func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
    if collectionView == allHobbiesCV {
        return allHobbiesArray.count
    }
    else {
        return myHobbiesArray.count
    }
}

代表

func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {

    if collectionView == allHobbiesCV {
        let cell = allHobbiesCV.cellForItem(at: indexPath) as! AllHobbiesCell

        myHobbiesArray.append(allHobbiesArray[indexPath.row])

        myHobbiesCV.reloadData()
        for i in 0..<allSelected.count {
            self.myHobbiesCV.selectItem(at: allSelected[i], animated: false, scrollPosition: [])
        }
    }

    else {
        let cell = myHobbiesCV.cellForItem(at: indexPath) as! MyHobbiesCell
        cell.backgroundColor = UIColor.red // Red background to show that it's selected

        // Store all of the selected cells in allSelected
        allSelected = self.myHobbiesCV.indexPathsForSelectedItems!

    }

}

func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath) {

    if collectionView == allHobbiesCV {
        let cell = allHobbiesCV.cellForItem(at: indexPath) as! AllHobbiesCell
        cell.backgroundColor = UIColor.yellow
    }
    else {
        let cell = myHobbiesCV.cellForItem(at: indexPath) as! MyHobbiesCell
        cell.backgroundColor = UIColor.yellow

        // update allSelected after deselect
        allSelected = self.myHobbiesCV.indexPathsForSelectedItems!

    }

}

正在删除单元格

@IBAction func deleteButtonPressed(_ sender: UIButton) {
    if allSelected.count > 0 {
        for element in allSelected {
            removeSelectedCells(i: element.item)
        }
    }
}

func removeSelectedCells(i: Int) {
    self.myHobbiesArray.remove(at: i) // This is what Xcode shows as the crash on the fatal error.
    let indexPath = NSIndexPath(row: i, section: 0)

    self.myHobbiesCV.deleteItems(at: NSArray(object: indexPath) as! [IndexPath])

    //self.myHobbiesCV.performBatchUpdates({
    //    self.myHobbiesCV.deleteItems(at: NSArray(object: indexPath) as! [IndexPath])
    //}) { (true) in
    //    self.myHobbiesCV.reloadData()
    //}
}

如果您能提供任何帮助来处理从集合视图中删除多个单元格,我们将不胜感激。如果您需要更多信息,我很乐意澄清。

使用 SO 答案 ,您应该能够从 indexPaths 的 allSelected 数组中获取索引,然后一次性从 myHobbiesArray 中删除索引。

@IBAction func deleteButtonPressed(_ sender: UIButton) {
    let indices = allSelected.map{ [=10=].item } 
    myHobbiesArray = myHobbiesArray.enumerated().flatMap { indices.contains([=10=].0) ? nil : [=10=].1 }
    self.myHobbiesCV.deleteItems(at: allSelected)
}