Swift - универсальные модели для разных ячеек табличного представления - PullRequest
0 голосов
/ 08 марта 2019

Я работаю над табличным представлением (похожим на мессенджер Facebook), в котором у меня разные типы ячеек (изображение, текст, видео и т. Д.) Я пытаюсь заархивировать файл: я хочу объявить список 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
}

Можно ли как-нибудь архивировать эту цель?

1 Ответ

1 голос
/ 08 марта 2019

Представьте, что ваши данные будут такими:

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

Давайте составим первый протокол, которому должна соответствовать каждая ячейка.

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. Добавьте TableCellConfigurator для этой ячейки в классе ViewModel.

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!")

Для получения дополнительной информации перейдите по этой ссылке

...