问题:如何通过扩展来编写UITableViewDataSource
的默认实现?
Swift支持协议扩展中的默认实现,UITableViewDataSource
是一种协议。那么为什么下面的例子不起作用呢?
我尝试了下面的示例,但表格保持空白。可以肯定的是,我在默认实现中添加了断点,但是没有达到它们。我把print
方法放在里面,但它们什么都不打印。
此扩展会使基本表视图的使用几乎无代码,因为它们只需要符合TableItem
的实体集合。
This question with similar title is unrelated.
完整示例:
import UIKit
/// Conform to this protocol to be immediatelly usable in table views.
protocol TableItem {
var textLabel: String? { get }
var detailTextLabel: String? { get }
}
protocol BasicTableDataSource {
associatedtype TableItemType: TableItem
var tableItems: [TableItemType]? { get set }
/// The table view will dequeue a cell with this identifier.
/// Leave empty to use `cellStyle`.
var cellIdentifier: String? { get set }
/// If `cellIdentifier` is empty, the table view will use this cell style.
/// Leave empty to use `UITableViewCellStyle.default`.
var cellStyle: UITableViewCellStyle? { get set }
}
extension UITableViewDataSource where Self: BasicTableDataSource {
func tableView(
_ tableView: UITableView,
numberOfRowsInSection section: Int) -> Int {
return tableItems?.count ?? 0
}
func tableView(
_ tableView: UITableView,
cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = cellIdentifier == nil
? UITableViewCell(
style: cellStyle ?? .default,
reuseIdentifier: nil)
: tableView.dequeueReusableCell(
withIdentifier: cellIdentifier!,
for: indexPath)
let tableItem = tableItems?[indexPath.row]
cell.textLabel?.text = tableItem?.textLabel
cell.detailTextLabel?.text = tableItem?.detailTextLabel
return cell
}
}
class ProductsTableViewController: UITableViewController, BasicTableDataSource {
var cellIdentifier: String?
var cellStyle: UITableViewCellStyle? = .subtitle
/// Product conforms to TableItem
var tableItems: [Product]? = Sample.someProducts()
}
答案 0 :(得分:0)
替换
extension UITableViewDataSource where Self: BasicTableDataSource
用
extension UITableViewDataSource
由于UITableViewDataSource
未向BasicTableDataSource
协议确认。所以它不会扩展UITableViewDataSource
More about Protocol Constraints了解向协议扩展添加约束。
答案 1 :(得分:-1)
答案:在扩展程序中编写UITableViewDataSource
方法的默认实现是不可能的。这是不行的。
Xcode现在显示错误:
非''@ objc'方法'tableView(_:numberOfRowsInSection :)'不满足'@objc'协议'UITableViewDataSource'的要求
非''objc'方法'tableView(_:cellForRowAt :)'不满足'@objc'协议'UITableViewDataSource'的要求
2017年2月,一位Swift核心团队成员将此问题was officially closed称为“不会做”,并显示以下消息。 More history on this Stack Overflow topic.
这是故意的:由于Objective-C运行时的限制,协议扩展无法引入@objc入口点。如果要将@objc入口点添加到NSObject,请扩展NSObject。
奇怪的是,当我将继承从UITableViewController
替换为UIViewController
时,Xcode才开始抱怨。这没有任何抱怨:
class ProductsTableViewController: UITableViewController, BasicTableDataSource {
var cellIdentifier: String?
var cellStyle: UITableViewCellStyle? = .subtitle
var tableItems: [Product]? = Sample.someProducts()
// Table already exists in UITableViewController
}
...但是这会让扩展开始抱怨:
class ProductsTableViewController: UIViewController, BasicTableDataSource, UITableViewDataSource {
var cellIdentifier: String?
var cellStyle: UITableViewCellStyle? = .subtitle
var tableItems: [Product]? = Sample.someProducts()
// Adding table manually...
var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
tableView = UITableView(frame: view.bounds)
view.addSubview(tableView)
}
}