我正在尝试将 tableView 更新为 UITableViewDiffableDataSource 但我无法删除/移动行。在上一个问题的帮助下,我对 dataSource 进行了子类化,并在那里添加了 tableview 覆盖。这些行将被编辑,但是当我离开并返回视图时,它们会回到原来的状态,因为我在 VC 中的数据模型没有随着编辑而更新。有人能帮忙吗?
extension NSDiffableDataSourceSnapshot {
mutating func deleteItemsAndSections(_ items : [ItemIdentifierType]) {
self.deleteItems(items)
let emptySection = self.sectionIdentifiers.filter {
self.numberOfItems(inSection: $0) == 0
}
self.deleteSections(emptySection)
}
}
fileprivate class ListDrillDownDataSource: UITableViewDiffableDataSource<String, ListItem> {
override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
return true
}
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
guard editingStyle == .delete else { return }
// Delete the row from the data source
if let item = self.itemIdentifier(for: indexPath) {
var snapshot = self.snapshot()
snapshot.deleteItemsAndSections([item])
self.apply(snapshot, animatingDifferences: true)
}
}
override func tableView(_ tableView: UITableView, canMoveRowAt indexPath: IndexPath) -> Bool {
return true
}
}
编辑**
我通过添加 backingStore 取得了一些进展,并且更接近能够更新现有单元格。然而,我最终只是一直陷入同一个错误循环中。
ListItem
我首先添加了一个值是自定义类的 backingStore 属性。该类可以使用 UUID() 作为属性之一进行哈希处理。
class ListDrillDownTableViewController: UITableViewController {
fileprivate var dataSource: ListDrillDownDataSource!
fileprivate var currentSnapshot: ListDrillDownSnaphot?
var list: List = List(name: "Test List", listStyle: .preSetStyle[0], listItems: [], users: [])
var backingStore = [UUID: ListItem]()
override func viewDidLoad() {
super.viewDidLoad()
self.navigationItem.leftBarButtonItem = self.editButtonItem
self.dataSource = createDataSource()
updateUI(animated: false)
tableView.rowHeight = 65
}
然后我创建了一个方法来创建数据源,为单元格提供程序提供 UUID 以查找 listItem。我还使用填充 UUID 和 backingStore 的初始快照更新了 UI。
fileprivate func createDataSource() -> ListDrillDownDataSource {
let dataSource = ListDrillDownDataSource(tableView: tableView) { (tableView, indexPath, uuid) -> UITableViewCell? in
let cell = tableView.dequeueReusableCell(withIdentifier: "ListItemCell", for: indexPath) as! ListItemCell
guard let listItem = self.backingStore[uuid] else { return cell }
cell.titleLabel.text = listItem.title
if let cost = listItem.cost {
cell.costLabel.isHidden = false
cell.costLabel.text = (listItem.costString(cost: cost))
} else {
cell.costLabel.isHidden = true
}
if listItem.note == "" {
cell.noteIcon.isHidden = true
} else {
cell.noteIcon.isHidden = false
}
if listItem.askToReschedule && !listItem.hasRepeatInterval {
cell.repeatIcon.isHidden = false
cell.repeatIcon.image = UIImage(systemName: "plus.bubble")
} else if !listItem.askToReschedule && listItem.hasRepeatInterval {
cell.repeatIcon.isHidden = false
cell.repeatIcon.image = UIImage(systemName: "repeat")
} else {
cell.repeatIcon.isHidden = true
}
return cell
}
self.tableView.dataSource = dataSource
return dataSource
}
func updateUI(animated: Bool = true) {
var snapshot = ListDrillDownSnaphot()
snapshot.appendSections(["main"])
let uuids = self.list.listItems.map { _ in UUID() }
snapshot.appendItems(uuids)
for (uuid, listItem) in zip(uuids, list.listItems) {
self.backingStore[uuid] = listItem
}
self.dataSource.apply(snapshot, animatingDifferences: animated)
}
最后,当用户点击一个单元格,进行编辑并点击完成时,视图展开回这个控制器,我尝试在展开方法中更新数据源。就目前而言,该应用程序将创建第一个新单元格,但是当尝试第二个单元格时,它会重新加载第一行两次,并且随着我不断添加它将现有行加倍。我猜是因为我一遍又一遍地附加整个列表,但我不知道如何访问附加的 uuid。
当我点击现有单元格并编辑它的信息时,它可以工作,但是如果我再次进入该行并出来,则该单元格会恢复到原来的状态。如果我继续尝试它会在原始状态和更新状态之间来回弹跳,就像它在快照之间来回弹跳一样?
@IBAction func unwindToListDrillDownTableView(_ unwindSegue: UIStoryboardSegue) {
// Verify the correct segue is being used.
guard unwindSegue.identifier == "DoneAddEditListItemUnwind" else { return }
let sourceViewController = unwindSegue.source as! ListItemDetailTableViewController
// Update the Lists categories with any changes.
self.list.listStyle?.categories = sourceViewController.currentCategories
// Verify a ListItem was returned.
if let listItem = sourceViewController.listItem {
// Check if ListItem is existing.
if let indexOfExistingListItem = list.listItems.firstIndex(of: listItem) {
// If existing, update the ListItem and then the view.
list.listItems[indexOfExistingListItem] = listItem
let uuid = self.dataSource.itemIdentifier(for: IndexPath(row: indexOfExistingListItem, section: 0))
let uuids = self.list.listItems.map { _ in UUID() }
var snapshot = self.dataSource.snapshot()
snapshot.reloadItems([uuid!])
for (uuid, listItem) in zip(uuids, list.listItems) {
self.backingStore[uuid] = listItem
}
self.dataSource.apply(snapshot, animatingDifferences: true)
} else {
// If new, add to listItems collection and update the view.
list.listItems.append(listItem)
if self.backingStore.keys.isEmpty {
updateUI()
} else {
var snapshot = self.dataSource.snapshot()
let uuids = self.list.listItems.map { _ in UUID() }
snapshot.reloadSections(["main"])
snapshot.appendItems(uuids)
for (uuid, listItem) in zip(uuids, list.listItems) {
self.backingStore[uuid] = listItem
}
self.dataSource.apply(snapshot, animatingDifferences: true)
}
}
}
}