ios - 在不使用条件的情况下为各种模型配置 UITableViewCell 实例
问题描述
我想处理许多不同的数据类型,每种数据类型都有一个关联的UITableViewCell
类和专用configure(for:)
函数。
目前我的视图控制器有这样的东西
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
func failure() {
fatalError("The row type was unknown, or the row item couldn't be cast as expected, or the specified cell couldn't be dequeued, or the dequeued cell couldn't be cast")
}
let section = sections[indexPath.section]
let item = section.rowItems[indexPath.row]
switch item.moduleType {
case .message:
guard let message = item as? CardModules.Message,
let messageCell = tableView.dequeueReusableCell(withIdentifier: CardCell_Message.identifier) as? CardCell_Message
else { failure(); break }
messageCell.configure(for: message)
return messageCell
case .availability:
guard let availability = item as? CardModules.Availability,
let availabilityCell = tableView.dequeueReusableCell(withIdentifier: CardCell_Availability.identifier) as? CardCell_Availability
else { failure(); break }
availabilityCell.configure(for: availability)
return availabilityCell
// etc, for many data types
我更喜欢一个系统,其中任何模型都可以通过视图控制器中的单个调用实例化它的单元类,并编写了以下解决方案
protocol DataForCell {
associatedtype Cell: CellForData
func configuredCell(from tableView: UITableView) -> Cell
}
extension DataForCell {
func cell(from tableView: UITableView) -> Cell {
let cell = tableView.dequeueReusableCell(withIdentifier: Cell.identifier) as! Cell
return cell
}
}
protocol CellForData {
associatedtype Data: DataForCell
static var identifier: String { get }
func configure(for data: Data)
}
这允许cellForRowAt
只调用configuredCell(from: tableView)
每个项目,因为项目数组是一个DataForCell
问题是,我该如何进一步改进呢?如果该configuredCell
功能可以移动到协议扩展中以避免需要在每个实例中将其保留为样板,那就太好了DataForCell
最后,这种方法是否违反任何重要原则?
更新 基于 Sweepers 的建议,改进的协议如下:
// MARK: - Data Protocol
protocol DataForCell {
associatedtype Cell: CellForData
}
extension DataForCell where Cell.Data == Self {
func configuredCell(from tableView: UITableView) -> Cell {
let cell = tableView.dequeueReusableCell(withIdentifier: Cell.identifier) as! Cell
cell.configure(for: self)
return cell
}
}
// MARK: - Cell Protocol
protocol CellForData {
associatedtype Data: DataForCell
static var identifier: String { get }
func configure(for data: Data)
}
解决方案
根据一个共同的细胞类别使用不同的细胞类型。
class BaseCellType : UITableviewCell {
func configure(…) {
print(“Not implemented”)
}
}
class MessageCell : BaseCellTyoe {
override func configure(…) {
… configure the message cell
}
}
然后在 TableViewDataSource 中创建一个单元格标识符字典:
let cellId : [ModuleType:String] = [.message : CardModule.message, …]
然后在 cellForRow 中,使用 BaseCellType 类型的正确标识符将单元格出列并调用配置。在情节提要中为每个单元格设置最终单元格类型。注意:您也可以使用协议来执行此操作。
推荐阅读
- python - 没有名为 influxdb 的模块
- llvm-lit - Lit-llvm - 获取当前目录(不是完整路径)
- excel - 对指定列但可变行的整个数据集进行自定义排序
- c# - 在 MediatR 命令/查询模式中传递会话数据
- react-native - 如何从堆栈导航器访问 navigation.toggleDrawer()?
- javascript - 在没有 AJAX 的情况下使用“WooCommerce 结帐时更改数量”插件
- ios - PHPickerViewController,双击图像调用didFinishPicking两次
- mysql - 石墨烯 Django 的 MySQL 复制
- sql - 如何在 Postgres 中将 3 个表组合在一起?
- java - 如何使用 Java Streams 合并对象中类型列表的成员,这样我们得到一个列表