简体   繁体   English

删除 tableview 单元格不会更新索引

[英]Deleting tableview cells won't update index

I have a UITableview with multiple delete functionality.我有一个具有多个删除功能的 UITableview。 When a user selects on a cell ie;当用户选择一个单元格时,即; row 5. It deletes that row, and every row prior (0...5).第 5 行。它删除该行以及之前的每一行 (0...5)。 Whilst in theory this works correctly.虽然理论上这可以正常工作。 The index path of the rows do not update when calling tableView.deleteRows(at:) within beginUpdates & endUpdates .beginUpdatesendUpdates中调用tableView.deleteRows(at:)时,行的索引路径不会更新。

One work around involves calling either reloadSections or reloadData however this yields unwanted behaviour since it prematurely ends the deleteRows animation.一种解决方法涉及调用reloadSectionsreloadData但这会产生不需要的行为,因为它会过早结束deleteRows animation。 And/or doing so after a delay.和/或延迟后这样做。 (ie below) (即下面)

DispatchQueue.main.asyncAfter(deadline: .now() + 0.25) {
   tableView.reloadSections(IndexSet(integer: 0), with: .none)
}
tableView.deselectRow(at: indexPath, animated: true)
tableView.beginUpdates()
var allIndexPaths = [IndexPath]()
for index in 0...indexPath.row {
    allIndexPaths.append(.init(row: index, section: 0))
}
self.tableData.removeSubrange(0...indexPath.row)
tableView.deleteRows(at: allIndexPaths, with: .fade)
tableView.endUpdates()

I created a test app to display this issue.我创建了一个测试应用程序来显示这个问题。

在此处输入图像描述 在此处输入图像描述

Scrolling down, and up again fixes this issue.向下滚动,然后再次向上滚动可解决此问题。 So it is obviously a dequeuing issue.所以这显然是一个出队问题。

Your code works as expected.您的代码按预期工作。 The "row 0" text is just that; “第 0 行”文本就是这样; text in a label. label 中的文本。 There is no dynamic binding between the row index and that label's text.行索引和该标签的文本之间没有动态绑定。

The only way you are going to see the row numbers update is if you explicitly reload the visible rows.您将看到行号更新的唯一方法是显式重新加载可见行。

override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    let allIndexPaths = (0...indexPath.row).map { IndexPath(row:$0, section:0) }
    self.tableData.removeFirst(indexPath.row+1)
    tableView.deleteRows(at: allIndexPaths, with: .fade)
        
    tableView.reloadRows(at: self.tableView.indexPathsForVisibleRows ?? [], with: .none)
}

Generally you wouldn't expose the row numbers to the user;通常,您不会向用户公开行号; they are just an implementation detail.它们只是一个实现细节。

Actually what you are expecting is exactly the opposite of what you should expect.实际上,您所期望的与您应该期望的完全相反。 You've misapprehended the purpose of batch updates.您误解了批量更新的目的。 The idea here is that the user is deleting the cell and its corresponding data.这里的想法是用户正在删除单元格及其相应的数据。 The table view is just a presentation of the data .表格视图只是数据的呈现。

Moreover, cells are reused.此外,细胞被重复使用。 So they need to be kept tied to the data they represent.因此,它们需要与它们所代表的数据保持联系。 Cells do not represent the row they happen to be in at that moment;单元格不代表它们当时恰好所在的 they represent the data corresponding to that row.它们代表与该行对应的数据 When cells are deleted, the corresponding data is deleted, and so the correspondence keeps working between all the rest of the cells and the data.当单元格被删除时,相应的数据也被删除,因此所有单元格的rest与数据之间的对应关系一直有效

To illustrate, forget about rows for a moment and think only about numbers .为了说明,暂时忘记行,只考虑数字 It may be that the cell in row 0 was associated with the data "0" to start with;可能是第 0 行中的单元格与数据“0”相关 but if the user deletes that row, what should happen is that that cell and the "0" are gone: That is what the user was trying to do: by way of the table, the user removes the data , which in this case is the "0".但是如果用户删除该行,应该发生的是该单元格和“0”消失了:这就是用户试图做的:通过表格,用户删除了数据,在这种情况下是“0”。

So now there is no "0" in the data.所以现在数据中没有“0”。 And the "0" must not magically return from the dead.而“0”绝不能神奇地死而复生。 But that is exactly what you try to make it do.但这正是你试图让它做的事情。 And so the results are incoherent.所以结果是不连贯的。

The error in your code, then, is that after the deletion you then proceed to make the data rise from the dead, by trying to reassociate the cells with the row number they happen to occupy now.那么,您的代码中的错误是,在删除之后,您继续通过尝试将单元格与它们现在恰好占据的行号重新关联来使数据起死回生。 No. The cell needs to be associated consistently with a piece of data.不可以。单元格需要始终与一条数据相关联。

So, in your resetData , change the key line populating the cell to this:因此,在您的resetData中,将填充单元格的关键行更改为:

textLabel?.text = "Piece of data: \(data.index)"

Suddenly the correct and expected behavior of the table view will spring to life — simply because you have let go of the misapprehension that a cell represents the index number of the row it happens to be in at the moment.突然之间,表格视图的正确和预期行为将使 spring 恢复生机 - 仅仅是因为您让 go 误认为一个单元格代表它恰好所在的行的索引号 It doesn't.它没有。 It represents the data at that index number.它表示该索引号处的数据

Data is user-facing.数据是面向用户的。 Index numbers are not.索引号不是。 And now you see what trouble you can get into by trying to make index number be user-facing!现在您知道尝试使索引号面向用户会遇到什么麻烦! Distinguish between model and view and all will be well.区分model视图,一切都会好起来的。 The view shows the user the model — it does not show the user facts about itself.该视图向用户显示model - 它不向用户显示有关其自身的事实。 View is not model;查看不是model; data is not stored in the interface, but in some sort of internal data storage.数据不存储在接口中,而是存储在某种内部数据存储中。 That, in fact, is exactly why table views have a data source.事实上,这正是表视图具有数据源的原因

Use performBatchUpdates instead.请改用performBatchUpdates

beginUpdates/endUpdates sometimes doesn't work somehow. beginUpdates/endUpdates 有时无法以某种方式工作。

---Update--- - -更新 - -

I ran the project you provided on Github.我在 Github 上运行了您提供的项目。 It worked well, I didn't see the problems you mentioned.效果很好,我没有看到你提到的问题。 So I can only guess, this happened base on the devices, especially for the simulators.所以我只能猜测,这发生在设备上,尤其是模拟器。

Try to put these codes bellow endUpdates to refresh the UI of tableview:尝试将这些代码放在endUpdates下面来刷新 tableview 的 UI:

tableView.setNeedsUpdateConstraints()
tableView.needsUpdateConstraints()
tableView.setNeedsLayout()
tableView.layoutIfNeeded()
tableView.superview.setNeedsLayout()
tableView.superview.layoutIfNeeded()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM