删除行 UITableView 索引问题

Posted

技术标签:

【中文标题】删除行 UITableView 索引问题【英文标题】:delete row UITableView index issue 【发布时间】:2017-04-29 07:00:06 【问题描述】:

我正在使用下面的代码删除我的表格视图中的一行。首先,我从数组中删除对象,然后使用以下代码从 tableview 中删除:

let i = IndexPath(item: rowNum, section: 0)
myArray.remove(at: rowNum)
myTableView.deleteRows(at: [i], with: UITableViewRowAnimation.left)

但是,如果我随后删除另一行,则不会删除我要删除的行。问题是,即使我删除了 tableview 中的第一项(例如索引 0),单击新的第一行返回索引 1 ......这是错误的,并删除了第二行。删除第一行后,顶部的新行的索引应为 0。

我可以通过这样做来解决这个问题:

mTableView.reloadData()

但这似乎是错误的......我不应该再次重新加载所有数据。

我还能做什么?

编辑:我的 tableviewcell 中有一个自定义按钮,我按下它来删除行 - 不是刷卡。

【问题讨论】:

删除你的数组中的项目后......你重新加载表......?如果不重新加载表格...它将解决您的问题 Tableview 总是返回正确的索引,你能告诉你删除索引方法,即你从哪里得到你的“rowNum” 查看链接:使用nsnotification中心***.com/questions/36279894/… 您的代码究竟是如何与按钮操作相关联的?您在哪里以及如何定义按钮目标? 如果您使用自定义按钮删除单元格,您从哪里获得rowNum 【参考方案1】:

问题

您的问题是您在 Button 上设置的 Tag ,当您删除 Rows 时,按钮 Tag 不会更改,因为它的 All Cell 没有重新加载。 我猜你是在cellforRowIndexpath 中设置标签,你尝试在tableWillDisplayCell 中将标签放在按钮上

最好的方法如下。

解决方案

您可以通过其他方式获取IndexPath

假设您的视图层次结构是

UITableViewCell-> contentView -> 按钮

在你的按钮点击方法

 if let cell = sender.superview?.superview as? UITableviewCell
        let indexPath = myTableView.indexPath(for: cell)
    // Now delete the table cell
    myArray.remove(at: indexPath.row)
    myTableView.beginUpdates()
    myTableView.deleteRows(at: [indexPath], with: UITableViewRowAnimation.left)
    myTableView.endUpdates()

我希望这对你有用。

【讨论】:

【参考方案2】:

我认为您将 rowNum 变量与您的单元格一起存储,并且它是在 cellForRow(at:) 方法中设置的。如果我认为是对的,那么这就是一件事。

UITableView 尽量做最少的工作。这意味着在您删除一个单元格后,UITableView 不会再次调用其数据源上的 cellForRow(at:) 方法,直到您调用 reloadData()reloadRows(at:animation:) 方法。

因此,当您删除第一个单元格时,其他单元格上的 rowNum 变量将不会更新,直到您尝试调用 reloadData() 并看到这是有效的。

我的建议是不要将rowNum 变量保留在单元格中,而是通过UITableView 上的indexPath(for:) 方法向UITableView 询问任何单元格的索引路径。

【讨论】:

【参考方案3】:

在相应单元格中按下按钮时删除一行的智能解决方案。

在自定义单元类中声明一个回调变量

  var callback : ((UITableViewCell)->())?

在自定义单元类中实现IBAction 并将按钮连接到该操作

  @IBAction func buttonPressed(_ sender : UIButton) 
     callback?(self)
  

cellForRowAtIndexPath 中分配包含删除单元格代码的闭包

  cell.callback =  currentCell in
      let actualIndexPath = tableView.indexPath(for: currentCell)!
      self.myArray.remove(at: actualIndexPath.row)
      tableView.deleteRows(at: [actualIndexPath], with: .left)
  

【讨论】:

这正是我正在做的事情。但是我得到了原始问题的错误。除非您调用 reloadData(),否则该闭包永远不会更新,这显然会重新加载所有数据。 我测试了代码。我确实工作。也许有额外的代码篡改了索引路径。 @vadian 我做了同样的事情postMedia.remove(at: indexPath.row) tableView.deleteRows(at: [indexPath], with: .automatic) .. 首先我删除了第一行,第二行应该是删除后的第一行,索引路径为 1 而不是 0,它显然崩溃了。不知道为什么删除行后表没有更新其索引路径。 @vadian 删除某个单元格后,我们是否还需要在选择表格单元格时获取实际的索引路径? @EICaptainv2.0 如果我正确理解你的问题,当didSelectRow 被调用时,你总是得到正确的索引路径【参考方案4】:

我不确定你从哪里得到你的 var rowNum,但在我看来,这个问题似乎已经发生在我身上。

对我来说,问题在于将tableView: cellForRowAt indexPath: 中的indexPath 传递给单元格会导致在删除单元格时不会更新此值。

也就是说,在被删除单元格的按钮之后排序的所有按钮的索引必须移动-1,否则它们将删除第n+1行。

row A index 0
row B index 1
row C index 2
row D index 3

删除B会发生

row A index 0
row C index 2
row D index 3

而C应该有索引1,D应该有索引2。在这种情况下点击按钮删除C会导致D被删除,点击按钮删除D会导致崩溃。

我希望我已经足够清楚了。

【讨论】:

【参考方案5】:

试试这个!

func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) 
    if editingStyle == .delete 

        //1. remove data from model
        data.remove(at: indexPath.row)

        //2. remove row from view
        tableView.deleteRows(at: [indexPath as IndexPath], with: .fade)
    

【讨论】:

我实际上在我的 tableviewcell 中有一个按钮,我想按下它来删除行。我怎样才能用你上面的代码做到这一点?【参考方案6】:

Use Apple's Code

表格视图的行为与在更新块内调用的重新加载方法相同 - 在执行动画块之前,重新加载是针对行和节的索引进行的。无论插入、删除和重新加载方法调用的顺序如何,都会发生此行为。

[tv beginUpdates];
[tv deleteRowsAtIndexPaths:deleteIndexPaths withRowAnimation:UITableViewRowAnimationFade];
[tv endUpdates];

【讨论】:

【参考方案7】:

删除行后,重新加载特定行

let indexPath = IndexPath(item: rowNum, section: 0)
array.remove(at: rowNum)
tableView.beginUpdates()
myTableView.deleteRows(at: [i], with: UITableViewRowAnimation.automatic)
tableView.endUpdates()
self.tableView.reloadRows(at: [indexPath], with: .automatic)

【讨论】:

【参考方案8】:

我在我的应用程序中使用以下代码:

public func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath)

    if editingStyle == UITableViewCellEditingStyle.delete
    
        myArray.remove(at: indexPath.row)
        myArray2.remove(at: indexPath.row)
        // you would also save the new array here so that the next time you open the tableview viewController it shows the changes made.

        mytableview.reloadData()

    

【讨论】:

【参考方案9】:

我遇到了这个问题,但以前的答案都没有对我有用。如果您在与myTableView.deleteRows(at:with:) 相同的块中运行myTableView.reloadData(),动画将无法正确运行。

您可以运行myTableView.performBatchUpdates(updates:completion:) 在更新处理程序中删除您的行并在完成处理程序中重新加载您的数据。这样,删除动画就可以正常运行,并且索引行会同步。

myTableView.performBatchUpdates(
    myTableView.deleteRows(at: [i], with: UITableViewRowAnimation.left)
, completion: finished in
    myTableView.reloadData()
)

【讨论】:

【参考方案10】:

如果你想从自定义按钮操作中删除 tableview 行,除了 tableview commit editingStyle delegate 或任何 tableview 委托方法,你必须调用 tableview reloadData 来填充更新的索引值。

【讨论】:

有没有办法在不重新加载整个 tableview 的情况下更新索引值?还是有其他方法可以做我想做的事? 你可以试试这个***.com/questions/35197766/…目标C这个->***.com/questions/29007807/…【参考方案11】:

任何插入或删除行的方法都必须在 tableView.beginUpdates()tableView.endUpdates() 之间调用。所以你的代码必须是:

let i = IndexPath(item: rowNum, section: 0)
myArray.remove(at: rowNum)

tableView.beginUpdates()

myTableView.deleteRows(at: [i], with: UITableViewRowAnimation.left)

tableView.endUpdates()

【讨论】:

那不正确,begin/endUpdates 仅在您必须同步或动画多个更新时才需要。

以上是关于删除行 UITableView 索引问题的主要内容,如果未能解决你的问题,请参考以下文章

UITableView 中同时插入/删除行的问题

表从数组中删除索引路径行值

使用“插入”行初始化 UITableView

如何从Storyboard中创建的静态UITableView中删除单元格

我如何使用 indexPath.Autorelease ?删除最后一个索引值

如何从 UITableView 获取行索引,其中数组列表由追加到类