Enums as constants


Swift enums are way more powerful than C/ObjC enums. For example, they are not limited to be mapped to Ints like in C but can also be e.g. Strings. And they also can contain methods inside them, quite like classes and struct.

That new feature opens a broad new usage for them, especially using them as specialized constants that produce types which were not possible to use as constants before. Let’s see some interesting use for that.

TL;DR: here is a nice tool to generate enums for all your constants, provided with a Playground to see the below examples in action.

Enums for your Image Assets

When you use the images of your Assets Catalog, you’re generally writing stuff like UIImage(named: "FooBar") to get the image of that name. The problem with that is that you need to remember exactly the name you gave to the image asset (did you name it "foobar", "FooBar", "foo_bar" or "foo-bar" in your assets catalog?), you are prone to typos, and you don’t have any kind of autocompletion.

Or course, you could declare a let FooBarImageName = "FooBar" constant somewhere in your code to avoid those problems, but having constants in the global space is not really cool as they are mixed with every other stuff, and are not clearly grouped with other constants representing image names. You could also group them in a static struct in the global namespace, but that’s still not very elegant.

So here comes the Swift enum. As Swift can have enums with a raw type String, you can write stuff like this:

enum ImageAsset : String {
  GreenApple = "green-apple"
  Banana = "banana"
  Pear = "pear"
  Strawberry = "1-strawberry"
  Strawberries = "strawberry-basket"
}

Adding constructors

That’s nice, but we can go further by adding a method (or better, a computed variable) that convert this enum into an UIImage.

extension ImageAsset {
  var image : UIImage {
    return UIImage(named: self.rawValue)!
  }
}

And here you go, now ImageAsset.GreenApple.image will return your UIImage. No risk of any typo at the call site here, free autocompletion, everything looks nice!

But hey, why not also make an UIImage constructor as well?

extension UIImage {
  convenience init(asset: ImageAsset) {
    self.init(named: asset.rawValue)!
  }
}

And now you can go use UIImage(asset: .GreenApple) too!

Given that this enum is actually so linked with UIImage, I like to declare it inside an UIImage extension instead of declaring it at the global scope.

Pretty cool, right?

Enums for your UIColors

But wait, why stop at UIImage? There is a lot of other stuff where you could apply that pattern too. For example, you typically have custom UIColors which you use everywhere in your code and that are tailored to your client’s corporate identity.

An enum of type UIColor?!

But how could we associate a raw type of UIColor to an enum? You can create enum of type Int or String, but using UIColor as the enum’s RawType is not possible.

That’s not really a problem, because we know other ways to represent colors: using their RGBA hex value (like ffcc00ff)! And your graphic designer actually probably gave you those color references in that #ffcc00 format anyway (as it’s also the one used in CSS), so that’s also nice to have a direct correspondance here.

So let’s use that instead, representing colors using some UInt32 enum, and take advantage of the 0x notation to affect each value using their hexadecimal representation.
We’ll also add it to the UIColor class as an extension, to scope it in that namespace instead of putting that enum the global scope:

extension UIColor {
  enum ColorName : UInt32 {
    case Translucent = 0xffffffcc
    case ArticleBody = 0x339666ff
    case Cyan = 0xff66ccff
    case ArticleTitle = 0x33fe66ff
  }
}

Ok, right, but now how do we build an UIColor instance from that?

We will simply need an initializer that use that UInt32, do some bitmask arithmetics on it to split it in 4 UInt8 components, and build an UIColor with that. Then, we will be able to write a convenience init to build a color from that enum:

extension UIColor {
  convenience init(named name: Name) {
    let rgbaValue = name.rawValue
    let red   = CGFloat((rgbaValue >> 24) & 0xff) / 255.0
    let green = CGFloat((rgbaValue >> 16) & 0xff) / 255.0
    let blue  = CGFloat((rgbaValue >>  8) & 0xff) / 255.0
    let alpha = CGFloat((rgbaValue      ) & 0xff) / 255.0
    
    self.init(red: red, green: green, blue: blue, alpha: alpha)
  }
}

UIColor(named: .ArticleBody)

That looks pretty handy!

Use enum constants everywhere!

There are plenty of other types for which enum as constants can be applied. Let’s look at two more example of what your code could look once you’ve implemented them for Strings and Storyboards (implementation for those enums are left as an exercice to the reader… or you can go check my Xcode Playground linked below).

Localizable.strings

You can use the same pattern for your Localizable.strings strings, for example, like creating the appropriate enum and adding a convenience init in a String extension, so that you could write String(key: .Greetings) instead of NSLocalizedString("Greetings", comment: ""). That’s pretty similar to how we implemented the UIImage(named: .SomeAsset) above.

You could go way further with that, by using the concept of “Associated Values” to pass arguments to your strings that use parameters (but that will be the subject of a dedicated article)

UIStoryboard

You can also use it for creating your UIStoryboard instances and their scenes / UIViewControllers (avoiding to use global-scope constants for the scene’s storyboardIDs/identifiers like a lot of us used to do in ObjC).

Wouldn’t it be cool to be able to write stuff like that?

let wizzardVC = UIStoryboard.Wizzard.initialViewController()
let msgCompVC = UIStoryboard.Message.Composer.viewController()
let tutorialVC = UIStoryboard.Tutorial.viewController(.QuickStart)

Well you got it, using enum of course it is possible!
One simple difference here is that we have an additional level of enums (There are actually multiple enums like Message and Composer, each having a case entry for each of their scene)

Automate all the things!

All that is pretty cool, but would need you to write a lot of enums and keep them all in sync when you create a new UIStoryboard, a new asset in your ImageCatalog, or add an entry in your Localizable.strings.

That’s where you think automation, of course.

I created a suite of tools called “SwiftGen”, available here in my GitHub, that are dedicated to this task.

These tools can automatically generate the code to create enums and the convenience init constructors for:

  • All your assets in your .xcassets Asset Catalog
  • All your UIStoryboard and their Scenes
  • All your strings in Localizable.strings
  • Even a tool to create the UIColor enum from a text file declaring them

Usage

You can use those tool to generate the code for your enums and create the appropriate .swift files, add those generated files in your Xcode project, and re-run the tools every time it’s needed when you added an Asset or Storyboard Scene.

These tools are written in Swift 2, and once compiled (using the provided Rakefile) into binary executables, are really fast to execute — even when they are parsing a big Localizable.strings file or a whole directory to search for .imageset asset files — so it shouldn’t even be a problem to make them execute as part of an “Script Build Phase” early in your build, to ensure that the code is always up-to-date each time you build your code.

Playground

My SwiftGen repository comes with an Xcode Playground so you can play with those “enum as constants” concepts and see them in action.

Enjoy!