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

Swift 尝试删除多个(以编程方式添加的)单元格后CollectionView崩溃,swift,crash,uicollectionview,uicollectionviewcell,Swift,Crash,Uicollectionview,Uicollectionviewcell,我有一个UICollectionView,它有一个非常简单的数据源。它只是一个以编程方式更新的字符串数组。使用此UICollectionView,我可以点击选择多个单元格,然后可以使用删除按钮删除所有选定的单元格。非常简单,只是我有时会遇到一个致命错误:索引超出范围 通过点击另一个名为“所有嗜好”的集合视图中的单元格,可以通过编程方式添加单元格。在“所有嗜好”CV中点击和选择的任何单元格都可以添加到“我的嗜好”中。我通过将点击单元格的值附加到控制“我的嗜好”CV的数组中来完成此操作 问题 根据我

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

通过点击另一个名为“所有嗜好”的集合视图中的单元格,可以通过编程方式添加单元格。在“所有嗜好”CV中点击和选择的任何单元格都可以添加到“我的嗜好”中。我通过将点击单元格的值附加到控制“我的嗜好”CV的数组中来完成此操作

问题

  • 根据我在爱好中选择的单元格,删除按钮(下面的代码)有时会删除这些单元格,有时会出现致命错误:索引超出范围。它在第一次删除时似乎不会崩溃(如果有帮助的话)
  • 如果我的嗜好中的单元格确实删除了,当我点击“所有嗜好”中的更多单元格时,它们会以UIColor.red(表示它们已被选中)的形式添加到“我的嗜好”中(然后在我按下“删除btn”按钮后将延迟崩溃)。单元格应以黄色添加
  • 似乎我的数据在删除后没有更新,当我再次尝试删除时,索引超出范围。然而,我在我的代码中找不到导致这种情况发生的问题(如果这真的是问题的话…)

    班级级别

    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!
    
        }
    
    }
    
    代表

    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!
    
        }
    
    }
    
    如果您能从集合视图中删除多个单元格,我们将不胜感激。如果您需要更多信息,我很乐意澄清。

    使用SO答案,您应该能够从索引路径的
    allSelected
    数组中获取索引,然后立即从
    myHobbiesArray
    中删除所有索引

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

    我想你有几个问题。每次删除时,您都在调用
    reloadData()
    。由于您正在调用
    performbatchUpdate
    ,因此不必重新加载collectionView。另外,
    performBatchUpdates
    方法用于一次执行多个更新(插入、删除、编辑)。因为您只是在删除,所以一次
    deleteItems(at:)
    调用就足够了。@dkw5877-我已经在代码和本文中进行了调整。但似乎没有解决我的问题。仍然随机发生崩溃。您只想调用一次
    performbatchUpdate
    ,而不是作为循环的一部分。尝试将其移动到“deleteButtonPressed”作为最后一行。基本上有两个步骤,从数据源中删除项目(
    myHobbiesArray
    ),然后调用
    deleteItems(at:)
    您应该能够使用
    allSelected
    数组作为
    PerformBatchUpdate
    的输入,类似于
    self.myHobbiesCV.deleteItems(at:allSelected)
    请参阅我之前的评论。假设您有一个选定的indexath.item数组
    [2,3]
    ,并且最初您有
    [0,1,2,3]
    的嗜好索引。您想从hobbie数组中删除项目2和3。第一次通过后,您的兴趣爱好索引为
    [0,1,2]
    ,然后尝试删除indexath.item=3,但该索引已不存在,因此您将崩溃。谢谢。这工作做得很好。我只需要温习一下map/flatMap方法。如果你不介意的话,你能再看一遍第二行在做什么吗?“myHobbiesArray=myHobbiesArray.enumerated().flatMap{index.contains($0.0)?nil:$0.1}”你真厉害!请参阅“另一个SO答案”链接,作者在该链接中详细解释了相关行。他还提供了一种替代实现。