在我的自定义单元格中,我有一个计时器。当倒计时达到0时,我调用我的委托方法,并自动删除单元格。
问题是,当第二个单元格达到0时,我的应用程序崩溃并出现错误fatal error: Index out of range
。
在我的自定义单元格中,我设置了数据:
protocol MyDelegateName {
func removeOfferExpired(offerId: String, indexPath: IndexPath)
}
class MyCustomCell: UITableViewCell {
var offer:Offers?
var cellIndexPath:IndexPath?
var delegate:MyDelegateName?
func setupData(offer:Offers, indexPath:IndexPath){
self.offer = offer
self.cellIndexPath = indexPath
//...other code not relevant
}
//When the time reach zero I call the following method
func updateTime() {
if timeLeft > 0 {
timeLeft = endTime.timeIntervalSinceNow
offerExpiresLabel.textColor = UIColor.white
offerExpiresLabel.text = timeLeft.hmmss
}else {
offerExpiresLabel.textColor = UIColor.red
offerExpiresLabel.text = "Offer Expired"
timer.invalidate()
self.delegate?.removeOfferExpired(offerId: (self.offer?.offer_id!)!, indexPath: self.cellIndexPath!)
}
}
在我的ViewController
中,我在cellForRowAt中设置了我的单元格数据:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let offer = offers[indexPath.row]
let cell = tableView.dequeueReusableCell(withIdentifier: cellId, for: indexPath) as! MyCustomCell
cell.setupData(offer: offer, indexPath: indexPath)
cell.delegate = self
return cell
}
然后在func removeOfferExpired(offerId: String, indexPath: IndexPath)
内我尝试使用:
1. self.offers.remove(at: indexPath.row)
self.tableView.reloadData()
2. self.offers.remove(at: indexPath.row)
self.tableView.deleteRows(at: [indexPath], with: .automatic)
self.tableView.reloadData()
3. //and even try to "wrap" it inside begin/end updates
tableView.beginUpdates()
self.offers.remove(at: indexPath.row)
self.tableView.deleteRows(at: [indexPath], with: .automatic)
tableView.endUpdates()
它总是第二次崩溃。据我所知,在setupData
中分配给单元格的indexPath在删除第一个单元格后不一样,但我认为reloadData
是更新其余单元格中的indexPath的方法。
答案 0 :(得分:2)
您的主要问题是,您告诉单元格其索引路径,然后您的单元格将该索引路径传递给其委托。但是单元格的索引路径并不稳定。它会随着添加,删除或移动其他行而更改。
您的单元协议的方法应将自身(单元格)作为参数传递,而不是索引路径。然后,委托可以查询表视图以查找单元的最新索引路径,并根据该最新的索引路径执行行删除。
答案 1 :(得分:0)
正如rmaddy所说,我所做的事情是完全错误的。这就是我根据他的回答所做的:
func updateTime() {
if timeLeft > 0 {
timeLeft = endTime.timeIntervalSinceNow
offerExpiresLabel.textColor = UIColor.white
offerExpiresLabel.text = timeLeft.hmmss
}else {
offerExpiresLabel.textColor = UIColor.red
offerExpiresLabel.text = "Offer Expired"
timer.invalidate()
// when the time reach zero I passed self to the delegate instead of the indexPath
self.delegate?.removeOfferExpired(offerId: (self.offer?.offer_id!)!, cell: self as UITableViewCell)
}
}
protocol MyDelegateName {
func removeOfferExpired(offerId: String, cell: UITableViewCell) // delegate method now passes the cell instead of the index
}
func removeOfferExpired(offerId: String, cell: UITableViewCell) {
// and then I get the index path from the cell
let indexPath = tableView.indexPath(for: cell)
self.offers.remove(at: (indexPath?.row)!)
self.tableView.deleteRows(at: [indexPath!], with: .automatic)
}