致命错误:第二次细胞删除时索引超出范围

时间:2017-04-25 22:25:17

标签: ios swift uitableview

在我的自定义单元格中,我有一个计时器。当倒计时达到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的方法。

2 个答案:

答案 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)
}