ios - swift (RxSwift) : Using generics to link ViewItem and Cell classes

标签 ios swift generics rx-swift

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

为此,我编写了一个方法,它接受一个实现我的 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
    }
}

函数方法配置了我的单元格:

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 出现问题:

Use of undeclared type '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
}

最佳答案

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

您可能能够在运行时通过泛型进行某种类型的转换来完成它,但是转换不允许您访问该类的属性,这可能是您执行所有绑定(bind)所需要的。我认为您最好将 switch 语句中的代码移动到 tableViewCell 设置中。

关于ios - swift (RxSwift) : Using generics to link ViewItem and Cell classes,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53498878/

相关文章:

ios - Singleton类中的Init方法(Objective-C)

ios cocos2d 2.0 使用什么代替 glNormalPointer

ios - swift : TableView Cells not getting selected correctly

swift - CGPath 的 PhysicsEditor 多边形路径

ios - 从另一个类(class) swift 获得 IBOutlet

Java:使用泛型作为抽象层

ios - 返回具有关联类型的协议(protocol)

iphone - 如何获取设备 token ?

ios - 如何在具有无限行的 UILabel 上自动换行?

Java 泛型 : put() on Map<String, 捕获#3-of ? extends AbstractClass> 不适用于参数 (String, AbstractClass)