I was reviewing some coding examples from Apple and I came across a fun sample application called Lucid Dreams. The purpose of this sample was to illustrate how to use “Protocol Oriented Programming” (POP). Within the example, I came across an interesting approach to static tables where you define a nested enum declaring the sections.

    enum Section: Int {
        case preview
        case description
        case numberOfCreatures
        case creature
        case effect
 
        static let count = 5
 
        var numberOfRows: Int {
            switch self {
                case .preview: return 0
                case .description: return 1
                case .numberOfCreatures: return 1
                case .creature: return Dream.Creature.all.count
                case .effect: return Dream.Effect.all.count
            }
        }
 
        /// A user facing title for the section to be used as a section header.
        var title: String? {
            switch self {
                case .description: return "Description"
                case .numberOfCreatures: return "Number of Creatures"
                case .creature: return "Creatures"
                case .effect: return "Effects"
 
                default: return nil
            }
        }
 
        init(at indexPath: IndexPath) {
            self.init(rawValue: indexPath.section)!
        }
 
        init(_ section: Int) {
            self.init(rawValue: section)!
        }
    }

Snippet from Apple’s Lucid Dreams

At first glance this does not seem like anything to write home about. However, when you take a step back and think about what this code does for us, it is pretty amazing. Lets discuss some of the benefits.

The Power

I have been a longtime advocate for Clean Code so this approach seems very acceptable. One of the main advantages of this pattern is testability. This eliminates the need to mock anything with life cycles and allows for a simple clean unit test.

A test can now be as simple as:


    func testDescriptionTitle() {
        XCTAssertNil(DreamDetailViewController.Section.preview.title)    
    }

Another advantage is the initializers. Since an initializer is provided for both the indexPath and the section we can now eliminate accessor code like:

    if index.section == 0 { return "Section title" }

We get this functionality for free for using the enum.

This power is not limited to the examples above. You will be able to add what ever methods that make sense for your use case.

The Beauty

The beauty of Swift, among other popular languages, is its declarative style. If we need to access the sections of the DreamDetailViewController we can write this in a more natural manner; DreamDetailViewController.Section(2).title or DreamDetailViewController.Section.creature.title. This allows for clear intent for the code you are working with.

The Dangers

As with everything that seems like a glorious solution there are some pitfalls to be aware of when selecting this option.

Inheritance

Inheritance, or lack there of, can be an issue. You may find yourself in a situation where you need to add another case to your enum. Well, with enums this is not an option. For a use case, lets look at feature toggling. For those that do not know, as its name implies, feature toggling is the act of toggling a feature but it is done in a more elegant way than littering if checks every where in your code base. One of the ways of providing a “feature” toggle is by creating a factory that will produce the correct output based on the feature toggle. So, if we look at the sections enum, lets say we are performing A/B testing and we want some people to have an extra section, say Friends. How would we do this? If this were a class we could simply create a child class and override or provide new functionality.

Dynamic Table Data

Dynamic table data will cause similar issues but with an added bonus. We can’t store data! Enums are not meant to store any data so by using this solution we will end up with something where we are now maintaining the data array outside of the sections enum and now we are starting to slip back into our old ways of accessing table data.

Wrapping Up

There are some ways you can get around the shortcomings of this approach. For instance, replacing the enum with a protocol but we’ll save that for another day. I hope this helps shine a light on how we can use enums to encapsulate data source information. Happy Coding!