首页 > 解决方案 > 在不使用条件的情况下为各种模型配置 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)
}

标签: iosswift

解决方案


根据一个共同的细胞类别使用不同的细胞类型。

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 类型的正确标识符将单元格出列并调用配置。在情节提要中为每个单元格设置最终单元格类型。注意:您也可以使用协议来执行此操作。


推荐阅读