5

I'm tinkering a bit with UITableViewDiffableDataSource and I'm able to get a tableView to load without issue. I'm trying to create section headers in the tableView, however I've encountered some flakey behavior.

The section enum enum defined as follows:

    enum AlertLevel: String, Codable, CaseIterable {
        case green = "green"
        case yellow = "yellow"
        case orange = "orange"
        case red = "red"
    }

This is my implementation for tableView(viewForHeaderInSection:)

    func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
        let label = UILabel()
        label.text = dataSource.snapshot().sectionIdentifiers[section].rawValue.capitalized
        label.textColor = UIColor.black

        return label
    }

That gives me 4 labels stacked in header cells at the top of my tableView.

I fired up Dash to RTFD and I saw tableView(titleForHeaderInSection:) is another way to skin that cat. So I threw this in, instead:

    func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
        return dataSource.snapshot().sectionIdentifiers[section].rawValue.capitalized
    }

I threw a breakpoint in and it never gets hit. So I implemented tableView(heightForHeaderInSection:) and the header gets updated, but no string displays for the header.

The table loads a LOT faster than it does "the old fashioned way" with IndexPaths (I'm using USGS earthquake database to learn TableViewDiffableDataSource), but I can't get the headers to show up.

Anyone got an idea of how to get sections working on a TableViewDiffableDataSource? I have a hard time believing they'd let something like this into the wild without such basic functionality, so I'm left to conclude I'm fouling something up...what, I don't know :)

Oh...and here's how I define my data source:

func makeDataSource() -> UITableViewDiffableDataSource<AlertLevel, Earthquake> {
    return UITableViewDiffableDataSource(tableView: tableView) { tableView, indexPath, earthquake in
        let cell = tableView.dequeueReusableCell(withIdentifier: self.reuseID, for: indexPath)
        cell.textLabel?.text = earthquake.properties.title
        cell.detailTextLabel?.text = earthquake.properties.detail

        return cell
    }
}
Adrian
  • 16,233
  • 18
  • 112
  • 180
  • Check that you’re using just on of the methods for setting the section header. So either use titleForHeaderInSection or viewForHeaderInSection, but don’t use both methods. – lacefarin Oct 26 '19 at 19:21
  • Yeah, I tried to do it one way, which didn't work. Neither did the other obvious way. I think I'm going to be Cortes and "burn the ships" with this and go full hog on SwiftUI, Combine, etc. – Adrian Oct 26 '19 at 23:10
  • heightForHeaderInSection - is a delegate method. that's why it's getting called. titleForHeaderInSection is not getting called because it's a data source method of a UITableViewDataSource protocol. And it doesn't work because you are using DiffableDataSource. You can't use both of them. – Tung Fam Oct 28 '19 at 18:59

1 Answers1

7

I was able to do that by subclassing the UITableViewDiffableDataSource class like this:

class MyDataSource: UITableViewDiffableDataSource<Section, Int> {

    override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
        let section = self.snapshot().sectionIdentifiers[section]
        return section.header
    }
}

where your Section is:

enum Section: Int {
    case one

    var header: String {
        switch self {
        case .one: return "Header One"
        }
    }
}

and then assign your newly created data source this way:

dataSource = MyDataSource<Section, Int>

meaning, you don't need to use UITableViewDiffableDataSource anymore, but use a subclassed MyDataSource class.

Tung Fam
  • 7,899
  • 4
  • 56
  • 63
  • That would return "Hello World!" for all of them. Any other tidbits that might be missing from the implementation? – Adrian Oct 27 '19 at 23:07
  • Yes, I can answer but I'm not sure what information you are looking for. Can you please specify? Inside this method you are able to get the itemIdentifier, sectionIndex. Both of these I think in 90% cases should cover use cases. But if there is anything else needed, please ask. @Adrian – Tung Fam Oct 27 '19 at 23:28
  • In case you haven't already figured it out, I'll suggest what I did to get different titles per section: I have my section IDs in an enum. In `titleForHeaderInSection` in my `UITableViewDiffableDataSource` subclass, I get the current section with `self.snapshot().sectionIdentifiers[section]`, switch over that, and return the right title for the section. Easy as crabapple pie! – AverageHelper Dec 01 '19 at 06:09
  • How to assign the DataSource without initializing. dataSource = MyDataSource
    – Yano Mar 24 '20 at 09:11