鉴于以下内容。
protocol EntityType {
var displayString: String { get }
}
extension String: EntityType {
var displayString: String { return self }
}
class GenericListViewController<Entity>: UIViewController, UITableViewDataSource, UITableViewDelegate where Entity: EntityType {
let items: [Entity]
let tableView: UITableView
init(items: [Entity]) {
self.items = items
self.tableView = UITableView()
super.init(nibName: nil, bundle: nil)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func loadView() {
super.loadView()
tableView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(tableView)
NSLayoutConstraint.activate([
tableView.topAnchor.constraint(equalTo: view.topAnchor),
tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor)
])
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "Cell")
tableView.dataSource = self
tableView.delegate = self
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return items.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
cell.textLabel?.text = items[indexPath.row].displayString
return cell
}
// func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
//
// }
}
class StringListViewController: GenericListViewController<String> {
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
print("selected: \(items[indexPath.row])")
}
}
为什么在具体的子类中调用tableView:didSelectRowAt:
?这适用于非泛型类型,或者当父类具有实现并且子类覆盖它时。这是预期的行为,Swift bug还是我错过了什么?
答案 0 :(得分:1)
这似乎是一个可能的错误。我猜它可能与Swift泛型对Objective-C运行时不可见的事实有关,所以即使直接在GenericListViewController<Entity>
中实现的方法被调用,也可能存在一些错误的行为。 Swift和Obj-C运行时试图找出覆盖。绝对值得一个错误报告。
我会注意到,在严格的OOP中,抽象超类通常不符合协议本身,它们只是提供默认实现。仍然需要具体的子类来声明协议一致性并填写任何缺少的实现。
对于上面的代码,您的GenericListViewController<Entity>
课程不应符合UITableViewDataSource
或UITableViewDelegate
。它只是提供了默认的方法实现,它允许具体的子类符合,而不必重写那些方法实现(除非需要覆盖)。您的StringListViewController
应该是声明符合这两个协议的那个。如果您修改代码来执行此操作,它实际上将按预期工作。
但这并没有改变你可能在Swift / Obj-C互操作中发现错误的事实。我相信你目前应该的工作,虽然它不是严格的OOP方式来处理协议一致性。