blukku
blukku

Reputation: 3

An efficient way to pick the type of custom UITableViewCell to return

I have a UITableViewController that renders out a number of rows containing custom types of UITableViewCell

The cells are divided in 2 categories, and then a further 3 sub categories.

system > text / media / interactive

user > text / media / interactive

I currently use a switch with a nested switch to assign the correct type of cell.

This however does not look or feel very nice. I don't feel this is the best way to achieve this but am unsure how else to approach this.

I am not using storyboards.

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let item = viewModel.history[indexPath.row]

    switch item.origin {
    case .system:
        switch item.type {
        case .text:
            let cell = tableView.dequeueReusableCell(withClass: BotMessageCell.self)
            cell.setContent(as: item)
            cell.layoutSubviews()
            return cell
        case .media:
            let cell = tableView.dequeueReusableCell(withClass: BotMediaCell.self)
            cell.setContent(as: item)
            cell.layoutSubviews()
            return cell
        case .interactive
            let cell = tableView.dequeueReusableCell(withClass: BotInteractiveCell.self)
            cell.setContent(as: item)
            cell.layoutSubviews()
            return cell
        default:
            fatalError("No dequeueReusableCell availble for cell of type \(item.type) ")
        }
    case .user:
        switch item.type {
        case .text:
            let cell = tableView.dequeueReusableCell(withClass: UserMessageCell.self)
            cell.setContent(as: item)
            cell.layoutSubviews()
            return cell
        case .media:
            let cell = tableView.dequeueReusableCell(withClass: UserMediaCell.self)
            cell.setContent(as: item)
            cell.layoutSubviews()
            return cell
        case .interactive
            let cell = tableView.dequeueReusableCell(withClass: UserInteractiveCell.self)
            cell.setContent(as: item)
            cell.layoutSubviews()
            return cell
        default:
            fatalError("No dequeueReusableCell availble for cell of type \(item.type) ")
        }
    }
}

Upvotes: 0

Views: 63

Answers (1)

vacawama
vacawama

Reputation: 154593

You could encode the class lookup into a dictionary which would greatly reduce the code:

// Protocol which all cells will adopt
protocol CustomCell {
    func setContent(as: Item)
}

// Here are the six classes which each must implement setContent()
class BotMessageCell: UITableViewCell, CustomCell { }
class BotMediaCell: UITableViewCell, CustomCell { }
class BotInteractiveCell: UITableViewCell, CustomCell { }
class UserMessageCell: UITableViewCell, CustomCell { }
class UserMediaCell: UITableViewCell, CustomCell { }
class UserInteractiveCell: UITableViewCell, CustomCell { }

// Enums for origin and item type    
enum Origin {
    case system
    case user
}

enum ItemType {
    case text
    case media
    case interactive
    case unknown
}

// Dictionary for looking up the class    
let dict: [Origin: [ItemType: AnyClass]] = [
    .system: [ .text:        BotMessageCell.self,
               .media:       BotMediaCell.self,
               .interactive: BotInteractiveCell.self
             ],
    .user:   [ .text:        UserMessageCell.self,
               .media:       UserMediaCell.self,
               .interactive: UserInteractiveCell.self
             ]
]

Then the code to get the cell becomes:

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let item = viewModel.history[indexPath.row]

    if let cellClass = dict[item.origin]?[item.type] {
        let cell = tableView.dequeueReusableCell(withClass: cellClass)
        (cell as? CustomCell)?.setContent(as: item)
        return cell
    }
    fatalError("No dequeueReusableCell availble for cell of type \(item.type) ")
}

Upvotes: 1

Related Questions