Swift (RxSwift):使用泛型链接 ViewItem 和 Cell 类

Posted

技术标签:

【中文标题】Swift (RxSwift):使用泛型链接 ViewItem 和 Cell 类【英文标题】:Swift (RxSwift): Using generics to link ViewItem and Cell classes 【发布时间】:2018-11-27 11:41:51 【问题描述】:

我正在重构 RxSwift 中的 UITableView 实现。我有不同的视图项,我想切换它们,以便能够相应地配置我的数据源。我需要知道哪个单元格类属于哪个视图项。

为此,我编写了一个方法,该方法采用实现我的ViewItemProtocol 并返回AnyClass? 的项目。

func getAssociatedtCellType<T>(for item: T) -> AnyClass? where T: ViewItemProtocol 
    switch item  
    case is TextFieldViewItem: return TextFieldCell.self
    case is FaqDetailViewItem: return FaqCell.self
    case is HeaderViewItem: return HeaderCell.self
    case is SubmitButtonViewItem: return SubmitButtonCell.self
    case is BankDetailViewItem: return BankDetailCell.self
    case is EmailViewItem: return EmailCell.self
    default: return nil
    

函数方法配置了我的cell:

private func configCell<T>(for item: T, with identifier: String, at indexPath: IndexPath) -> UITableViewCell where T: ViewItemProtocol 
    guard let cellType = getAssociatedtCellType(for: item.self) else  return UITableViewCell() 
    guard let cell = tableView.dequeueReusableCell(withIdentifier: identifier, for: indexPath) as? cellType else  fatalError() 
    cell.configureBindings(itemSource: item)
    return cell

问题出在cellType

使用未声明的类型'cellType'

背后的目标是重构这个方法:

private func dataSource() -> RxTableViewSectionedReloadDataSource<SectionedViewItem> 

    let dataSource = RxTableViewSectionedReloadDataSource<SectionedViewItem>(configureCell:  [unowned self] _, tableView, indexPath, item in

        switch item 
        case let item as TextFieldViewItem:
            guard let cell = tableView.dequeueReusableCell(withIdentifier: TextFieldCell.Key, for: indexPath) as? TextFieldCell else  fatalError() 
            cell.configureBindings(itemSource: item)
            cell.changeButton.isHidden = item.editable
            cell.changeButton.addTarget(self, action: #selector(self.showFieldNotEditableAlert), for: .touchUpInside)
            cell.textField.addTarget(self, action: #selector(self.textFieldDidChange), for: .editingChanged)
            return cell

        case let item as FaqDetailViewItem:
            guard let cell = tableView.dequeueReusableCell(withIdentifier: FaqDetailCell.Key, for: indexPath) as? FaqDetailCell else  fatalError() 
            cell.configureBindings(itemSource: item)
            return cell

        case let item as PasswordTextFieldViewItem:
            guard let cell = tableView.dequeueReusableCell(withIdentifier: PasswordTextFieldCell.Key, for: indexPath) as? PasswordTextFieldCell else  fatalError() 
            cell.configureBindings(itemSource: item)
            return cell

        case let item as HeaderViewItem:
            guard let cell = tableView.dequeueReusableCell(withIdentifier: HeaderCell.Key, for: indexPath) as? HeaderCell else  fatalError() 
            cell.configureBindings(itemSource: item)
            return cell

// ... My other cell types... :-(

    )

    dataSource.titleForHeaderInSection =  dataSource, index in
        let section = dataSource[index]
        return section.header
    

    return dataSource

...变成这样的:

private func dataSource() -> RxTableViewSectionedReloadDataSource<SectionedViewItem> 

    let dataSource = RxTableViewSectionedReloadDataSource<SectionedViewItem>(configureCell:  [unowned self] _, tableView, indexPath, item in

        switch item 
        case let item as TextFieldViewItem:
            guard let cell = tableView.dequeueReusableCell(withIdentifier: TextFieldCell.Key, for: indexPath) as? TextFieldCell else  fatalError() 
            cell.configureBindings(itemSource: item)
            cell.changeButton.isHidden = item.editable
            cell.changeButton.addTarget(self, action: #selector(self.showFieldNotEditableAlert), for: .touchUpInside)
            cell.textField.addTarget(self, action: #selector(self.textFieldDidChange), for: .editingChanged)
            return cell

        case let item as FaqDetailViewItem, let item as PasswordTextFieldViewItem, let item as HeaderViewItem:
            return configCell(for: item, with: "Cell.Key... still to implement)", at: indexPath)


        default:
            return UITableViewCell()
        

    )

    dataSource.titleForHeaderInSection =  dataSource, index in
        let section = dataSource[index]
        return section.header
    

    return dataSource

【问题讨论】:

【参考方案1】:

不幸的是,这不能在 Swift 中完成。在 swift 中,编译器需要在编译时知道变量的类型,但在你的情况下,你试图在运行时向下转换。所以不,你将无法做到这一点。

您可能可以在运行时使用泛型进行某种转换来完成它,但转换不会让您访问该类的属性,这可能是您进行所有绑定所需的。我认为最好将 switch 语句中的代码移动到 tableViewCell 设置中。

【讨论】:

感谢您的解释! :-)

以上是关于Swift (RxSwift):使用泛型链接 ViewItem 和 Cell 类的主要内容,如果未能解决你的问题,请参考以下文章

RxSwift

Swift 响应式编程

swift RxSwift - 使用 - extension.swift

Swift 4“调用中的额外参数”Rxswift

RXSwift的一些基本交互(OC,Swift,RXSwift对比)

Swift  之 RxSwift