UITableViewDataSource扩展,默认实现

时间:2017-12-20 03:53:02

标签: swift uitableview swift-protocols

问题:如何通过扩展来编写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()

}

2 个答案:

答案 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)
    }

}