Skip to content

EdgarDegas/EnumeratedTable

Repository files navigation

EnumeratedTable

Build Status Swift Version

An elegant way to layout a static table using Swift enum.

Preview

Chaos in your setting view controller code? Try enum.

Enumerate your sections and rows like this.

Outlined by Xcode clearly.

While keep your view controller clean.

And finally, the table you get.

Getting Started

Prerequisites

Cocoapods

Install cocoapods if you have not. Then add this line to your podfile:

pod 'EnumeratedTable', '~> 0.0.6'

Swift Package Manager

First make sure you are using Xcode 11.0 or later.

Then, go to File -> Swift Packages -> Add Package Dependency...

Search for EnumeratedTable

Quick Tutorial

First of all, consider the Example project in this repository a best practice.

1. Conform your table view controller to TableEnumerated:

extension ViewController: TableEnumerated {
    // ...
}

2. Enumerate your sections:

extension ViewController: TableEnumerated {
    enum Section: Int, SectionEnumeration {
        case user
        case setting
    }
}

3. Enumerate rows for each section:

extension ViewController: TableEnumerated {
    enum UserRow: Int, RowEnumeration {
        case avatar
        case biography
        
        var text: String? {
            switch self {
            case .avatar:
                return "iMoe"
            case .biography:
                return "A developer."
            }
        }
        
        var reuseIdentifier: String? {
            switch self {
            case .avatar:
                return "Avatar Cell"
            case .biography:
                return "Cell"
            }
        }
    }

    enum RichTextRow: Int, RowEnumeration {
        case row1
        case row2
        
        var text: String? {
            switch self {
            case .row1:
                return "Lorem ipsum dolor sit amet, consectetur adipiscing elit."
            case .row2:
                return "Ut enim ad minim veniam."
            }
        }
        
        var reuseIdentifier: String? {
            return "Rich Cell"
        }
    }
    
    enum Section: Int, SectionEnumeration {
        case user
        case setting
        
        var RowsInSection: RowEnumerated.Type {
            switch self {
            case .user:
                return ViewController.UserRow.self
            case .setting:
                return ViewController.RichTextRow.self
        }
    }
}

4. Use shortcut methods to layout your table view:

extension ViewController: UITableViewDataSource {
    func numberOfSections(in tableView: UITableView) -> Int {
        return numberOfEnumeratedSections
    }
    
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return numberOfEnumeratedRows(in: section)
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        return enumeratedCell(at: indexPath, inside: tableView)
    }
}

Make use of RowEnumeration

1. Besides from text, you can also provide rowHeight in your row enumeration:

    enum SelectableRow: Int, RowEnumeration {
        case about
        case githubRepo

        var text: String? {
            switch self {
            case .about:
                return "About EnumeratedTable"
            case .githubRepo:
                return "GitHub Repository"
            }
        }
        
        var height: CGFloat? {
            return 56
        }
    }

2. Return the row height in your controller's delegate implementation:

    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return enumeratedRow(at: indexPath)?.height ?? UITableView.automaticDimension
    }

Benefit from Enum

As default, you can provide text, detail (fits in the detail label of a UITableViewCell instance) and height.

But since enumerations are enum (of course), you can provide whatever value you want.

1. Provide headline, subhead:

extension ViewController: TableEnumerated {
    // ...
    
    enum RichTextRow: Int, RowEnumeration {
        case row1
        case row2
        
        var text: String? {
            switch self {
            case .row1:
                return "Lorem ipsum dolor sit amet, consectetur adipiscing elit."
            case .row2:
                return "Ut enim ad minim veniam."
            }
        }
        
        var headline: String {
            switch self {
            case .row1:
                return "Row 1"
            case .row2:
                return "Row 2"
            }
        }
        
        var subhead: String {
            switch self {
            case .row1:
                return "Subhead 1"
            case .row2:
                return "Subhead 2"
            }
        }
    }
        
    // ...
}

2. Conform your custom cells to Enumerable:

extension RichTextTableViewCell: Enumerable {
    func configure(using enumerated: RowEnumerated) {
        let enumerated = enumerated as! ViewController.RichTextRow
        headlineLabel.text = enumerated.headline
        subheadLabel.text = enumerated.subhead
        bodyLabel.text = enumerated.text
    }
}

extension AvatarTableViewCell: Enumerable {
    func configure(using enumerated: RowEnumerated) {
        let enumerated = enumerated as! ViewController.UserRow
        nameLabel.text = enumerated.text
        avatarImageView.image = enumerated.image
    }
}

Handle selection

1. Implement the handleSelection method in your row enumeration:

extension ViewController: TableEnumerated {
    // ...
    
    enum SelectableRow: Int, RowEnumeration {
        case about
        case githubRepo
        
        func handleSelection(by viewController: UIViewController) {
            switch self {
            case .about:
                viewController.performSegue(withIdentifier: "Show About", sender: nil)
            case .githubRepo:
                let url = URL(string: "https://github.com/EdgarDegas/EnumeratedTable")!
                let safariViewController = SFSafariViewController(url: url)
                viewController.present(safariViewController, animated: true)
            }
        }
    }
    
    // ...
}

2. Call the shortcut method in your controller's delegate implementation:

extension ViewController: UITableViewDelegate {
    // ...
    
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        handleSelection(at: indexPath, by: self)
    }
    
    // ...
}