【问题标题】:UITableViewDataSource extension with default implementation具有默认实现的 UITableViewDataSource 扩展
【发布时间】:2017-12-20 03:53:01
【问题描述】:

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

}

【问题讨论】:

  • 您是否尝试在viewDidLoad() 中调用.reloadData() 方法?
  • 我试过.reloadData(),在这种情况下它什么也没做
  • 你在哪里设置dataSource?像这样的东西:self.dataSource = self
  • UITableViewController 设置dataSource 本身,它不是UIViewController

标签: swift uitableview swift-protocols


【解决方案1】:

替换

extension UITableViewDataSource where Self: BasicTableDataSource

extension UITableViewDataSource

由于UITableViewDataSource 未确认BasicTableDataSource 协议。所以它不会扩展UITableViewDataSource

More about Protocol Constraints 了解向协议扩展添加约束。

【讨论】:

    【解决方案2】:

    答案:不可能在扩展中编写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 入口点。如果你想给 NSObject 添加 @objc 入口点,扩展 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)
        }
    
    }
    

    【讨论】:

      猜你喜欢
      • 2019-08-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-19
      • 1970-01-01
      相关资源
      最近更新 更多