移动/删除 Diffable TableView 行

问题描述

我正在尝试将 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,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,list.listItems) {
                    self.backingStore[uuid] = listItem
                }
                self.dataSource.apply(snapshot,animatingDifferences: true)
            }
        }
    }
}

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)