刪除 tableview 單元格不會更新索引 (Deleting tableview cells won't update index)


問題描述

刪除 tableview 單元格不會更新索引 (Deleting tableview cells won't update index)

我有一個具有多個刪除功能的 UITableview。當用戶選擇一個單元格時,即;第 5 行。它刪除該行以及之前的每一行 (0...5)。雖然理論上這可以正常工作。在 beginUpdates & 中調用 tableView.deleteRows(at:) 時行的索引路徑不會更新 endUpdates.

一種解決方法涉及調用 reloadSectionsreloadData 但這會產生不需要的行為,因為它會過早地結束 deleteRows 動畫。和/或延遲後這樣做。(即如下)

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()

我創建了一個測試應用來顯示這個問題。

在此處輸入圖片描述 在此處輸入圖片描述

向下滾動,然後再次向上修復此問題。所以這顯然是一個出隊問題。


參考解法

方法 1:

Your code works as expected. The "row 0" text is just that; text in a 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.

方法 2:

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.

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; 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".

So now there is no "0" in the data. And the "0" must not magically return from the dead. 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:

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. 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. The view shows the user the model — it does not show the user facts about itself. View is not 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.

方法 3:

Use performBatchUpdates instead.

beginUpdates/endUpdates sometimes doesn't work somehow.

‑‑‑Update‑‑‑

I ran the project you provided on 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:

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

(by Harry JPaulw11mattirons163)

參考文件

  1. Deleting tableview cells won't update index (CC BY‑SA 2.5/3.0/4.0)

#iOS #swift #uitableview






相關問題

將 jpg UIImage 轉換為位圖 UIImage? (convert jpg UIImage to bitmap UIImage?)

C++ Xcode iOS 項目錯誤 (C++ Xcode iOS project errors)

如何將以下行添加到我的 plist 文件中? (How can I add the following lines to my plist file?)

XCode 4.6 顯示方法 + (void)beginAnimations:(NSString *)animationID context:(void *)context; 的內存洩漏警告 (XCode 4.6 shows a warning of memory leak for method + (void)beginAnimations:(NSString *)animationID context:(void *)context;)

隨機分佈精靈 (randomly distribute sprites)

在 iOS 9 的 alert.addAction 中按下 OK 時如何打開另一個視圖控制器 (How to open another view controller when OK is pressed in alert.addAction in iOS 9)

在復選框上單擊獲取表行 ID - 目標 c (On check box click get the table Row ID - Objective c)

提交應用程序 - 添加本地化,但我的語言未列在組合框中? (Submitting app - Add Localizations, but my language is not listed in the combo box?)

是否可以從命令行更新 iOS 配置文件? (Can iOS Provisioning Profiles be renewed from the command-line?)

如何為collectionviewcell的刪除自定義動畫? (How to custom animation for collectionviewcell's deletion?)

由 LPLinkView 和 UIImageView 組成的單元格的 CollectionView 速度很慢,並且在滾動時會重新加載數據 (CollectionView with Cells made up of LPLinkView's and UIImageView's is Slow and Reloads Data While Scrolling)

刪除 tableview 單元格不會更新索引 (Deleting tableview cells won't update index)







留言討論