【问题标题】:Swift - Generic models for different table view cellsSwift - 不同表格视图单元格的通用模型
【发布时间】:2019-03-08 06:58:36
【问题描述】:

我正在处理一个表格视图(类似于 Facebook 的 Messenger),其中我有不同的单元格类型(图像、文本、视频等)。 我要归档的是,我想声明一个message model 列表,并且我将配置 tableView 以便单元格将由模型本身确定和配置。为了做到这一点,我需要以某种方式告诉model 它与哪个UITableViewCell 类相关联。基本上我想要一个这样的协议:

protocol ChatMessageDisplayable {
   static var myCellType: UITableViewCell { get } //Defines the UITableViewCell class this model is associated with
   func configure(cell: /*the associated cell type*/) // Let the model itself configure the cell.
}

然后我在我的ViewController中,我会声明一个数组

messageModels = [ChatMessageDisplayable]

还有我的 UITableViewDataSource 实现:

public func numberOfSections(in tableView: UITableView) -> Int {
    return messageModels.count
}

public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let model = messageModel[indexPath.row]


    let cellIdentifier = /* Name of the UITableViewCell this model is associated with */


    let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath)


    model.configure(cell: cell)
    return cell
}

无论如何我可以归档这个目标吗?

【问题讨论】:

  • 这可能是您问题的答案:youtube.com/watch?v=lpTNaBUFkno
  • 这对我的目标没有帮助,他的方法仅在表格视图只有一种类型的单元格时才有效。在我的情况下,我需要显示不同的单元格类型
  • 您是否有任何理由要使用协议来设置单元格的类型,而不是在 cellForRowAt 内使用 if 语句或 switch ?
  • If 语句。随着单元格数量的增加,它会变得巨大且不可读。
  • 然后使用switch语句来设置不同case的cell类型。

标签: swift uitableview generics


【解决方案1】:

想象一下你的数据会是这样的:

class TableViewModel {
    let items: [Any] = [
        User(name: "John Smith", imageName: "user3"),
        "Hi, this is a message text. Tra la la. Tra la la.",
        Bundle.main.url(forResource: "beach@2x", withExtension: "jpg")!,
        User(name: "Jessica Wood", imageName: "user2"),
        "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat."
    ]
}

所以通常我们会在tableView(_:cellForRowAt:) 方法中实现它,其中包含许多if let ...

防止这种情况的一种方法是使用泛型类型。泛型编程是避免样板代码的绝佳方式,有助于在编译期间定义错误。

通用代码使您能够编写灵活、可重用的函数和 可以与任何类型一起使用的类型,具体取决于您的要求 定义。您可以编写避免重复并表达其 以清晰、抽象的方式表达意图。 Apple Documentation

让我们制定每个单元应遵循的第一个协议。

protocol ConfigurableCell {
    associatedtype DataType
    func configure(data: DataType)
}

//example of UserCell
class UserCell: UITableViewCell, ConfigurableCell {
    @IBOutlet weak var avatarView: UIImageView!
    @IBOutlet weak var userNameLabel: UILabel!

    func configure(data user: User) {
        avatarView.image = UIImage(named: user.imageName)
        userNameLabel.text = user.name
    }
}

现在我们可以创建一个通用的单元格配置器来配置我们的表格单元格。

protocol CellConfigurator {
    static var reuseId: String { get }
    func configure(cell: UIView)
}

class TableCellConfigurator<CellType: ConfigurableCell, DataType>: CellConfigurator where CellType.DataType == DataType, CellType: UITableViewCell {
    static var reuseId: String { return String(describing: CellType.self) }

    let item: DataType

    init(item: DataType) {
        self.item = item
    }

    func configure(cell: UIView) {
        (cell as! CellType).configure(data: item)
    }
}

现在我们需要对 ViewModel 进行一些调整:

typealias UserCellConfigurator = TableCellConfigurator<UserCell, User>
typealias MessageCellConfigurator = TableCellConfigurator<MessageCell, String>
typealias ImageCellConfigurator = TableCellConfigurator<ImageCell, URL>

class TableViewModel {
    let items: [CellConfigurator] = [
        UserCellConfigurator(item: User(name: "John Smith", imageName: "user3")),
        MessageCellConfigurator(item: "Hi, this is a message text. Tra la la. Tra la la."),
        ImageCellConfigurator(item: Bundle.main.url(forResource: "beach@2x", withExtension: "jpg")!),
        UserCellConfigurator(item: User(name: "Jessica Wood", imageName: "user2")),
        MessageCellConfigurator(item: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat."),
    ]
}

就是这样!

您无需编辑 ViewController 的代码即可轻松添加新单元格。

让我们在表格视图中添加一个WarningCell。

1.符合ConfigurableCell协议。 2.在 ViewModel 的类中为该单元格添加 TableCellConfigurator。

class WarningCell: UITableViewCell, ConfigurableCell {
    @IBOutlet weak var messageLabel: UILabel!

    func configure(data message: String) {
        messageLabel.text = message
    }
}

//cell configurator for WarningCell
TableCellConfigurator<WarningCell, String>(item: "This is a serious warning!")

更多信息请关注link

【讨论】:

  • 谢谢,我试试看
  • 你将如何从 didselectrowatindexpath 编辑数据模型
  • 如何在表格视图单元格中更新数据模型
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-12-08
  • 1970-01-01
  • 1970-01-01
  • 2014-10-22
  • 2018-02-26
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多