Reputation: 1953
I am refactoring an UITableView
implementation in RxSwift. I have different view items and I want to switch them so that I am able to configure my dataSource accordingly. I need to know which cell class belongs to which view item.
To do so, I wrote a method that take an item which implement my ViewItemProtocol
and returns 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
}
}
The function method configured my 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
}
The problem arises with cellType
:
Use of undeclared type 'cellType'
The objective behind is to refactor this method:
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
}
... into something like this:
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
}
Upvotes: 0
Views: 165
Reputation: 1575
Unfortunately that cannot be done in Swift. In swift, the compiler needs to know the types of the variables at compile time but in your case you are trying to downcast at runtime. So no, you won't be able to do that.
You will probably be able to get it done with some sort of conversion with generics at runtime but the casting won't let you access the properties from that class, which is probably what you need to do all the bindings. I think you will be better off moving the code that you have in your switch statement to the tableViewCell setup.
Upvotes: 1