Yes, you read it right. Although many times, we uses enums and switch but there is a much more maintainable and readable configuration pattern by using struct. I first read it here on Jesse Squires blog.

Very often, we use enums to filter different configuration in our code. I often use it in a custom UITableViewCell class.

Example, in a mobile commerce app, we have a LineItemTableViewCell that is displaying the status of the line item.

struct LineItem {
    let productName: String
    let price: Double
    let status: String
}
enum LineItemTableViewCellStyle {
    case cart
    case deliveryStatus
    case orderHistory
}
class LineItemTableViewCell: UITableViewCell {
    @IBOutlet weak var productNameLabel: UILabel!
    @IBOutlet weak var priceLabel: UILabel!
    @IBOutlet weak var orderStatusLabel: UILabel!

    func configure(lineItem: LineItem) {
        productNameLabel.text = lineItem.productName
        priceLabel.text = "\(lineItem.price)"
        orderStatusLabel.text = lineItem.status
    }

    func applyStyle(_ style: LineItemTableViewCellStyle) {
        switch style {
        case .cart:
            orderStatusLabel.textColor = UIColor.black
            orderStatusLabel.isHidden = true
            isUserInteractionEnabled = true
            accessoryType = .none
        case .deliveryStatus:
            orderStatusLabel.textColor = UIColor.red
            orderStatusLabel.isHidden = false
            isUserInteractionEnabled = true
            accessoryType = .disclosureIndicator
        case .orderHistory:
            orderStatusLabel.textColor = UIColor.blue
            orderStatusLabel.isHidden = false
            isUserInteractionEnabled = true
            accessoryType = .disclosureIndicator
        }
    }
}

The LineItemTableViewCell is being use by different tableView. Like CartViewController, DeliveryStatusViewController and OrderHistoryViewController. Each will call the cell.applyStyle(style:) for different style.

Let say we decide to allow user to review their order. We will add a new ReviewViewController using LineItemTableViewCell as well. But we also have to add a new .reviewOrder into our enum and switch.

func applyStyle(_ style: LineItemTableViewCellStyle) {
    switch style {
    case .cart:
        orderStatusLabel.textColor = UIColor.black
        orderStatusLabel.isHidden = true
        isUserInteractionEnabled = true
        accessoryType = .none
    case .deliveryStatus:
        orderStatusLabel.textColor = UIColor.red
        orderStatusLabel.isHidden = false
        isUserInteractionEnabled = true
        accessoryType = .checkmark
    case .orderHistory:
        orderStatusLabel.textColor = UIColor.blue
        orderStatusLabel.isHidden = false
        isUserInteractionEnabled = true
        accessoryType = .disclosureIndicator
    case .reviewOrder:
        orderStatusLabel.textColor = UIColor.blue
        orderStatusLabel.isHidden = false
        isUserInteractionEnabled = true
        accessoryType = .disclosureIndicator
    }
}

This add more lines to the applyStyle() and become more difficult to read. We are just toggling the properties of the UILabel and cell. Sometimes I wonder if I could have a default style and just change those that need to be change. Thanks to Jesse, I learn a new and better way of doing it.

So instead of using enum and switch we can actually use struct to do it. The new applyStyle() will look like this:

func applyStyle(_ style: LineItemCellStyle) {
    orderStatusLabel.textColor = style.labelColor
    orderStatusLabel.isHidden = style.hideLabel
    isUserInteractionEnabled = style.allowInteraction
    accessoryType = style.accessoryType
}

The LineItemCellStyle is a struct that preset all the common pattern.

struct LineItemCellStyle {
    let labelColor: UIColor
    let hideLabel: Bool
    let allowInteraction: Bool
    let accessoryType: UITableViewCellAccessoryType

    init(labelColor: UIColor = UIColor.black, hideLabel: Bool = false, allowInteraction: Bool = true,
      accessoryType: UITableViewCellAccessoryType = .none) {
        self.labelColor = labelColor
        self.hideLabel = hideLabel
        self.allowInteraction = allowInteraction
        self.accessoryType = accessoryType
    }

    static var cartStyle: LineItemCellStyle {
        return LineItemCellStyle(hideLabel: true)
    }

    static var deliveryStyle: LineItemCellStyle {
        return LineItemCellStyle(labelColor: UIColor.red, allowInteraction: false, accessoryType: .checkmark)
    }

    static var historyStyle: LineItemCellStyle {
        return LineItemCellStyle(labelColor: UIColor.blue, accessoryType: .disclosureIndicator)
    }

    static var reviewStyle: LineItemCellStyle {
        return LineItemCellStyle(accessoryType: .disclosureIndicator)
    }
}

The advantage of this approach is a cleaner LineItemTableViewCell. We no longer have a massive switch statement but instead a custom struct to manage the different cell style. Default properties can also be preset in the init instead of settings it again and again.

If you notice that your custom UITableViewCell or any other switch and enum configuration is getting massively huge, consider this approach. I really like this and already refactor most of my project with this. It is a lot easier to write test for it as well!