swift 使用UITableView和UITableViewDiffableDataSource在UIViewController中滑动删除

llycmphe  于 2022-12-10  发布在  Swift
关注(0)|答案(1)|浏览(135)

我有一个UIViewController,其中包含一个UICollectionView和一个UITableView。这两个视图分别使用UICollectionViewDiffableDataSourceUITableViewDiffableDataSource
在表中,我尝试为删除操作设置swipe功能。对于常规数据源来说,这是一个非常简单的任务,但我无法让它与diffable数据源一起工作。
我尝试为UITableViewDiffableDataSource创建一个自定义类,但我甚至无法编译代码,因为我尝试从控制器访问该属性。(我需要访问存储模型的属性,以便不仅删除行,还删除数据。)使用UITableViewDelegatetableView(leadingSwipeActionsConfigurationForRowAt:)确实编译了,我可以滑动,但应用程序崩溃并出现错误:* 作为UITableView的数据源时,必须通过UITableViewDiffableDataSource API更新UITableView *。
我该怎么做?有没有适合做这种工作的最佳实践?
编辑1:
根据评论中的要求,我提供了一些代码,用于最近的实现尝试。
UIViewController中(这是一个很长的实现,所以我省略了大部分):

class ViewController: UIViewController, ItemsTableViewDiffableDataSourceDelegate {

    @IBOutlet var tableView: UITableView!

    var items = [Item]()
    var tableViewDataSource: ItemsTableViewDiffableDataSource!
    var itemsSnapshot: NSDiffableDataSourceSnapshot<String, Item> {
        var snapshot = NSDiffableDataSourceSnapshot<String, Item>()
        snapshot.appendSections(["Items"])
        snapshot.appendItems(items)
        return snapshot
    }

    func configureTableViewDataSource() {
        // A working implementation
    }

    func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
        let deleteAction = UIContextualAction(style: .destructive, title: "Delete") { action, view, handler in
            self.items.remove(at: indexPath.row)
            tableView.deleteRows(at: [indexPath], with: .fade)
        }
        deleteAction.backgroundColor = .red
        let configuration = UISwipeActionsConfiguration(actions: [deleteAction])
        configuration.performsFirstActionWithFullSwipe = false
        return configuration
    }
}

UITableViewDiffableDataSource中(完整实现):

@MainActor
class ItemsTableViewDiffableDataSource: UITableViewDiffableDataSource<String, Item> {
}

protocol ItemsTableViewDiffableDataSourceDelegate: AnyObject {
    func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration?
}

最初,我在数据源类中定义了tableView(leadingSwipeActionsConfigurationForRowAt:)方法,但我无法访问items属性,所以我尝试使用一个协议。无论哪种方式,实现都不起作用-我无法滑动,更不用说删除项和表行了。
编辑二:
我猜真实的的问题是--如何用我的tableView注册tableView(leadingSwipeActionsConfigurationForRowAt:)方法。

t3psigkw

t3psigkw1#

事实证明,实现相当简单,在我的例子中不需要定制的UITableViewDiffableDataSource类,整个实现都进入了视图控制器。

class ViewController: UIViewController, UITableViewDelegate {
    
    @IBOutlet var tableView: UITableView!
    
    var items = [Item]()
    var tableViewDataSource: UITableViewDiffableDataSource<String, Item>!
    var itemsSnapshot: NSDiffableDataSourceSnapshot<String, Item> {
        var snapshot = NSDiffableDataSourceSnapshot<String, Item>()
        snapshot.appendSections(["Items"])
        snapshot.appendItems(items)
        return snapshot
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        configureTableViewDataSource()
        tableView.delegate = self
    }
        
    func configureTableViewDataSource() {
        tableViewDataSource = UITableViewDiffableDataSource<String, Item>(tableView: tableView, cellProvider: { (tableView, indexPath, itemIdentifier) -> UITableViewCell? in
            let cell = tableView.dequeueReusableCell(withIdentifier: ItemTableViewCell.reuseIdentifier, for: indexPath) as! ItemTableViewCell
            cell.configureCell(for: itemIdentifier)
            return cell
        })
    }
    
    func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
        let deleteAction = UIContextualAction(style: .destructive, title: "Delete") { action, view, handler in
            self.items.remove(at: indexPath.row)
            self.tableViewDataSource.apply(self.itemsSnapshot, animatingDifferences: true)
        }
        deleteAction.backgroundColor = .red
        let configuration = UISwipeActionsConfiguration(actions: [deleteAction])
        configuration.performsFirstActionWithFullSwipe = true
        return configuration
    }
}

请记住将视图控制器设置为表视图的委托,这可以在viewDidLoad()中实现(感谢HangarRash在注解中的提示)。
我在尝试这种方法时的第一个错误是,我仍然试图通过直接操作表视图来更新数据。

***由于未捕获的异常“NSInternalInconsistencyException”,正在终止应用程序,原因:'当UITableView充当UITableView的数据源时,必须通过UITableViewDiffableDataSource API更新UITableView:请不要直接在UITableView上调用变体API。

请改为调用self.tableViewDataSource.apply(self.itemsSnapshot, animatingDifferences: true)

相关问题