'UITableViewDiffableDataSource: how to set section header titles?
I am trying to set up an UITableView with sections using the new UITableViewDiffableDataSource within an UITableViewController.
Everything seems to work fine except setting the section header titles.
According to Apple's documentation, UITableViewDiffableDataSource conforms to UITableViewDataSource, so I was expecting this to be possible.
I have tried:
- overriding tableView(_ tableView:, titleForHeaderInSection section:) in the UITableViewController class
- subclassing UITableViewDiffableDataSource and implementing tableView(_ tableView:, titleForHeaderInSection section:) in the subclass
but both ways lead to no result (Xcode 11 and iOS13 beta 3).
Is there currently a way to set the section header titles using UITableViewDiffableDataSource?
Solution 1:[1]
Providing code example on @particleman's explanations.
struct User: Hashable {
var name: String
}
enum UserSection: String {
case platinum = "Platinum Tier"
case gold = "Gold Tier"
case silver = "Silver Tier"
}
class UserTableViewDiffibleDataSource: UITableViewDiffableDataSource<UserSection, User> {
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
guard let user = self.itemIdentifier(for: IndexPath(item: 0, section: section)) else { return nil }
return self.snapshot().sectionIdentifier(containingItem: user)?.rawValue
}
}
Solution 2:[2]
Let me suggest quite a flexible universal solution:
Declare a subclass:
class StringConvertibleSectionTableViewDiffibleDataSource<UserSection: Hashable, User: Hashable>: UITableViewDiffableDataSource<UserSection, User> where UserSection: CustomStringConvertible {
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return sectionIdentifier(for: section)?.description
}
}
Usage example:
class ComitsListViewController: UITableViewController {
private var diffableDataSource = StringConvertibleSectionTableViewDiffibleDataSource<String, Commit>(tableView: tableView) { (tableView, indexPath, commit) -> UITableViewCell? in
let cell = tableView.dequeueReusableCell(withIdentifier: "Commit", for: indexPath)
cell.configure(with: commit)
return cell
}
}
You are not limited just to String thought. You can control what to display as section title by implementing description var of CustomStringConvertible protocol for your section type.
Solution 3:[3]
After you init self.dataSource to a UITableViewDiffableDataSource (which sets itself to the tableView.dataSource) set the tableView.dataSource back to self, i.e. the UITableViewController subclass. Now in your numberOfSectionsInTableView and numberOfRowsInSection methods forward those to self.dataSource and return its info (this is the composition pattern). Now your UITableViewController just implements its section titles as normal since it is the table's data source.
I believe UITableViewDiffableDataSource should not be setting itself as the dataSource if one is already set but I guess they designed it to work in the least error prone way because with UITableViewController added to a storyboard its already set.
If you do it this way then it makes sense why the class wasn't open in the early iOS 13 betas.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Brandon WongKS |
| Solution 2 | Paul B |
| Solution 3 | malhal |
