Reputation: 3
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
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