Creating a theme helper

:  ~ 1 min read

The standard approach for this would be something like this:

struct Theme {
  enum Color {
    case title
    case subtitle
    // [...]
    var color: UIColor {
      switch self {
      case .title: return UIColor.red
      case .subtitle: return UIColor.blue
      ...
      }
    }
  }
  
  enum Font {
  }
}

And using it throughout the app would look like this:

func customLabel(text: String, color uiColor: Theme.Color, font uiFont: Theme.Font) {
  [...]
  label.textColor = color.uiColor
  label.font = font.uiFont
  [...]
}

let myLabel = customLabel(
  text: "Pretty label", 
  textColor: .title, 
  textFont: .title
)
myLabel.textColor = Theme.Color.subtitle.color
myLabel.font = Theme.Font.subtitle.font

Another approach would be with nested structs and static constants for avoiding the color / font computed property (at the cost of slight, but unnecessary extra memory usage):

struct Theme {
  struct Color {
    static let title = UIColor.red
    static let subtitle = UIColor.blue
    ...
  }
}

I find this approach pretty neat, but I'm not really sold vs simple extensions:

extension UIColor {
  static var title: UIColor { return UIColor.red }
  static var subtitle: UIColor { return UIColor.blue }
  ...
}
extension UIFont {
  ...
}

And the usage would be the one we're all already familiar with, which involves a lot less typing, too:

func customLabel(text: String, color: UIColor, font: UIFont) {
  [...]
  label.textColor = color
  label.font = font
  [...]
}

let myLabel = customLabel(
  text: "Pretty label", 
  textColor: .titleColor, // This is neatly inferred.
  textFont: .titleFont
)
myLabel.textColor = .subtitle
myLabel.font = .subtitle