Swift 尝试删除多个(以编程方式添加的)单元格后CollectionView崩溃
我有一个UICollectionView,它有一个非常简单的数据源。它只是一个以编程方式更新的字符串数组。使用此UICollectionView,我可以点击选择多个单元格,然后可以使用删除按钮删除所有选定的单元格。非常简单,只是我有时会遇到一个致命错误:索引超出范围 通过点击另一个名为“所有嗜好”的集合视图中的单元格,可以通过编程方式添加单元格。在“所有嗜好”CV中点击和选择的任何单元格都可以添加到“我的嗜好”中。我通过将点击单元格的值附加到控制“我的嗜好”CV的数组中来完成此操作 问题Swift 尝试删除多个(以编程方式添加的)单元格后CollectionView崩溃,swift,crash,uicollectionview,uicollectionviewcell,Swift,Crash,Uicollectionview,Uicollectionviewcell,我有一个UICollectionView,它有一个非常简单的数据源。它只是一个以编程方式更新的字符串数组。使用此UICollectionView,我可以点击选择多个单元格,然后可以使用删除按钮删除所有选定的单元格。非常简单,只是我有时会遇到一个致命错误:索引超出范围 通过点击另一个名为“所有嗜好”的集合视图中的单元格,可以通过编程方式添加单元格。在“所有嗜好”CV中点击和选择的任何单元格都可以添加到“我的嗜好”中。我通过将点击单元格的值附加到控制“我的嗜好”CV的数组中来完成此操作 问题 根据我
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答案”链接,作者在该链接中详细解释了相关行。他还提供了一种替代实现。