使用基于协议或基类的泛型参数值将子类上的方法调用到UITableViewCell

Sun*_*kas 9 generics ios swift

我想简化在UITableViewCell子类中调用"setup"方法的过程.但是,并非所有设置方法都相同,但它们的参数继承自相同类型.是否可以使用泛型或协议不必每次都抛出参数?

首先,我是一个像这样的cellForRow方法:

class DataSource<V : UIViewController, T: TableViewCellData, VM: ViewModel> : NSObject, UITableViewDataSource, UITableViewDelegate {

    var dataCollection: TableViewDataCollection<T>!
    var viewModel: VM!

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cellData = dataCollection.object(for: indexPath)
        let cell = tableView.dequeueReusableCell(withIdentifier: cellData.identifier(), for: indexPath)
        if let setupableCell = cell as? CellDataSetupable {
            setupableCell.setup(with: cellData, viewModel: viewModel)
        }
        return cell
    }
}

protocol CellDataSetupable : class {
    func setup(with cellData: TableViewCellData, viewModel: ViewModel)
}
Run Code Online (Sandbox Code Playgroud)

我使用cellData和viewModel设置单元格.

在我的(很多)自定义UITableViewCell子类中:

extension BlurbTableViewCell : CellDataSetupable {
    func setup(with cellData: TableViewCellData, viewModel: ViewModel) {
        guard let cellData = cellData as? HomeViewTableViewCellData else { return }
        guard let viewModel = viewModel as? HomeViewModel else { return }

        // Use cellData and viewModel to setup cell appearance 
    }
}
Run Code Online (Sandbox Code Playgroud)

where HomeViewTableViewCellData的子类是TableViewCellDataHomeViewModel的子类ViewModel

相反,我想删除警卫并直接写这样的东西:

extension BlurbTableViewCell : CellDataSetupable< {
    func setup(with cellData: HomeViewTableViewCellData, viewModel: HomeViewModel) {   
        // Use cellData and viewModel to setup cell appearance 
    }
}
Run Code Online (Sandbox Code Playgroud)

尝试的解决方案(不起作用):

有什么想法或我必须和我的铸件一起生活吗?

编辑1: 在Nate Mann的建议下面我尝试了这段代码(注意我已经重命名了一些泛型类型):

// This works fine
extension TransactionTableViewCell : CellDataSetupable {
    typealias CellData = HomeViewTableViewCellData
    typealias VM = HomeViewModel
    func setup(with cellData: CellData, viewModel: VM) {
        //Setup cell appearance ...
    }
}
Run Code Online (Sandbox Code Playgroud)

这行也可以正常工作:(注意额外的where子句)

class DataSource<VC : UIViewController, TVCD: TableViewCellData, VM: ViewModel, CDS: CellDataSetupable> : NSObject, UITableViewDataSource, UITableViewDelegate where CDS.TVCD == TVCD, CDS.VM == VM {
    // ...

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cellData = dataCollection.object(for: indexPath)
        let cell = tableView.dequeueReusableCell(withIdentifier: cellData.identifier(), for: indexPath)
        if let setupableCell = cell as? CDS {
            setupableCell.setup(with: cellData, viewModel: viewModel)
        }
        return cell
    }
Run Code Online (Sandbox Code Playgroud)

但改变了

class HomeTableViewDataSource: DataSource<HomeViewController, HomeViewTableViewCellData, HomeViewModel> {
Run Code Online (Sandbox Code Playgroud)

class HomeTableViewDataSource: DataSource<HomeViewController, HomeViewTableViewCellData, HomeViewModel, CellDataSetupable> {
Run Code Online (Sandbox Code Playgroud)

给出这个错误:

Using 'CellDataSetupable' as a concrete type confirming to protocol 'CellDataSetupable' is not supported
Run Code Online (Sandbox Code Playgroud)

编辑2:使用UITableViewCell类的通用基类的具体版本是不可能的.请参阅为什么界面构建器不能使用UIView的具体通用子类?

Sun*_*kas 1

我自己的想法是,目前不可能。

内特·曼的回答要求我指定一个CellDataSetupable我不想要的具体实现。

timaktimak 的答案要么需要具体的实现,要么需要 UIView 的子类化。