Cleaner Table View Data Source Code with CaseIterable

I’ve had a real drive to clean up my table view code when switching between cells and sections. I’ve been craving a data structure that keeps track of:

  • The sections in a table view.
  • The classes that are used in that section, and
  • the reuse identifier.

A couple months ago I stumbled upon a solution to this problem when I found a new protocol in Swift 4 called CaseIterable. I wrote this code to support some simple repeated logic in table view, which cleaned up a lot of code and made it a lot safer. An example:

    enum CellSection: String, CaseIterable {

        case overview = "Overview"
        case schools = "School"
        case jobs = "Job"
        case skills = "Skill"
        case projects = "Project"
        case other = "Other"
    
    }

Now by defining my sections as an string enum, I was able to clean up my data source code. For instance, my numberOfSections(in:) method became:

    override func numberOfSections(in tableView: UITableView) -> Int {
        return Section.allCases.count
    }

This became safer than simply hardcoding the return value, as it changed with the enum case changes. Additionally, I’ve occasionally made the string in this enum both the ReuseIdentifier and the classname for the cell class. For example:

    enum CellSection: String, CaseIterable {

        case overview = “Resume.OverviewCell”
    
    }

By doing this I can make my registration process more declarative.

    tableView.register(NSClassForString(CellSection.overview.rawValue), forCellReuseIdentifier: CellSection.overview.rawValue)

In my tableView(_:cellForRowAt:) method I started using:

        let section = CellSection.allCases[indexPath.section]
    let cell = tableView.dequeueReusableCell(withIdentifier: section.rawValue, for: indexPath)

Because CaseIterable returned the section in the order it was defined, my CellSection enum declared the type of cells available in the order that appeared. This made my table view data source code more declarative. Additionally, I avoided a problem I’ve seen many times before where indexPath.section is compared against a hardcoded integer in many spots in a data source. A good example implementation would be a sample tableView(_:numberOfRowsInSection:) implementation:

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        
        let section = CellSection.allCases[section]
        
        switch section {
        case .overview:
            return modelArray.count
        }
    }

Now, if I introduce a new section, I need to implement it in this switch. If I’m not going to use this section, I simply return 0. If Since switches in Swift must be exhaustive, I get an additional compile time check to ensure I haven’t implemented this data source improperly. If I decide I don’t need that safety I can use a default case.

By adding that, I’ve cleaned up my table view code so that the table view’s sections are much more apparent and added so safety checks to prevent me from hanging myself later on.

Safe Layout Guides and iPhone X.

Looking through the simulator on iOS 11 on an iPhone X the genesis for the safeAreaLayoutGuide API became so obvious to me. To account for the notch and the rounded corners of the screen, Apple added information about the sides of the screen as well as the top and bottom for us to use. (The latter being conveyed in the now deprecated topLayoutGuide and bottomLayoutGuide). I’m still not exactly sure how to “embrace the notch” in my projects though.

Regex101.com

I wish I had a tool like this while coding a several scripts a couple years ago; It’s compatible with PCRE, Python and JavaScript regex syntax. The explanation sidebar is killer.