我创建了一个测试项目来重现这个问题https://github.com/msnazarow/DiffarableTest
你只需要通过几个步骤
- 创建新目标
- 创建继承
UITableViewDiffableDataSource
和UITableViewDelegate
但不实现UITableViewDelegate
方法的Base
类 - 在另一个目标(主要为简化)继承
Base
类和实现任何UITableViewDelegate
方法(例如didSelectRowAt
) - 所有的实现方法都不起作用
您必须在BaseDataSource
类中配置委托函数,以便在子类中被覆盖。
extension MyDataSource
:
中注释掉didSelectRowAt
函数extension MyDataSource {
// func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
// print("CELL SELECTED")
// }
}
和实现didSelectRowAt
在BaseDataSource
:
open class BaseDataSource<T: Model & Hashable>: UITableViewDiffableDataSource<Int, T>, UITableViewDelegate {
public init(tableView: UITableView) {
super.init(tableView: tableView) { tableView, indexPath, model in
let cell = tableView.dequeueReusableCell(withIdentifier: "MyCell", for: indexPath) as! Configurable
cell.configure(with: model)
return cell as? UITableViewCell
}
}
public func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
print("Base Cell Selected", indexPath)
}
}
当你运行应用程序并点击第三行时,你应该得到调试输出:
Base Cell Selected [0, 2]
要在子类中实现它,你可以重写它:
extension MyDataSource {
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
print("MyDataSource Cell Selected", indexPath)
}
}
不能覆盖来自扩展的非动态类声明…所以在BaseDataSource
:
中设置为动态open class BaseDataSource<T: Model & Hashable>: UITableViewDiffableDataSource<Int, T>, UITableViewDelegate {
public init(tableView: UITableView) {
super.init(tableView: tableView) { tableView, indexPath, model in
let cell = tableView.dequeueReusableCell(withIdentifier: "MyCell", for: indexPath) as! Configurable
cell.configure(with: model)
return cell as? UITableViewCell
}
}
public dynamic func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
print("Base Cell Selected", indexPath)
}
}
点击第三行现在应该输出:
MyDataSource Cell Selected [0, 2]
注意如果没有子类化委托,BaseDataSource
中的didSelectRowAt
将被调用。另外,如果你想要一些代码也在BaseDataSource
中运行didSelectRowAt
,您可以从子类调用super
:
extension MyDataSource {
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
super.tableView(tableView, didSelectRowAt: indexPath)
print("MyDataSource Cell Selected", indexPath)
}
}
和选择第三行输出:
Base Cell Selected [0, 2]
MyDataSource Cell Selected [0, 2]
编辑
经过更多的研究,这被一些人认为是一个"bug"。
然而,一个很大的变化是Swift最初做的,但不再,推断@objc
。当需要将@objc
添加到函数(例如在选择器中使用时)时,每个人都遇到过这种情况。
那么,有两种方法来处理这个…
首先,如上所示,实现"什么都不做";
在子类中重写任何表视图委托函数。 第二个选项,听起来像是您更喜欢的,是在子类(或其扩展)中声明@objc
方法:
extension MyDataSource {
// add this line
@objc (tableView:didSelectRowAtIndexPath:)
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
print("MyDataSource extension Cell Selected", indexPath)
}
}
现在你可以回到你的原始代码,你只需要添加一行来获得所需的功能。