Blog

Swift Tip: Refactoring to Associated Values

We’re in the process of rewriting our Swift Talk backend from Ruby to Swift. Rather than trying to get everything right straight away, we typically port things over by writing Swift code with a very similar structure to the Ruby code. We make sure that everything works as expected, and only then do we refactor the code to be more Swift-like.

As an example, on the Episode page we show the user one of four things:

  • “Become a subscriber to download episode videos.”
  • “Re-downloading episodes doesn’t use any download credits.”
  • “You have (creditsLeft) download credits left”
  • “No download credits left. You’ll get new credits at the next billing cycle.”

In Ruby, the four cases were modeled as an enum, and we did the same in Swift:

enum DownloadStatus {
  case notSubscribed
  case reDownload
  case canDownload
  case noCredits
}

To generate the text above, we can write an extension on DownloadStatus:

extension DownloadStatus {
  func text(creditsLeft: Int) -> String {
    switch self {
       // ...
    }
  }
}

This works as expected, but after using it for a while we realized that passing on the creditsLeft everywhere — from the database, to the “controller” layer, to the view, to this method — can be a little annoying. It’s also a little annoying to make up a value for the notSubscribed case. In fact, the only place where we need it is in the canDownload case.

To remedy these annoyances, we refactored our DownloadStatus enum to include an associated value:

enum DownloadStatus {
        case notSubscribed
        case reDownload
        case canDownload(creditsLeft: Int)
        case noCredits
}

With this in place, we don’t have to pass on the creditsLeft separately, we can include it directly in the canDownload case. This also makes it possible to write text(creditsLeft:) as a computed property text:

var text: String {
  switch self {
    // ...
  }
}

Changing our code to use associated values gives us clearer code, and more importantly, instead of passing two parameters around in multiple places we now embed the second parameter in the DownloadStatus enum.

To learn more about enums, take a look at our books: Functional Swift shows how enums can help you write simpler code, and Advanced Swift gives a more in-depth account of how they function.

You can buy both books as part of the Swift Essentials bundle, with a little discount to say thank you. 🙏


Stay up-to-date with our newsletter or follow us on Twitter.

Back to the Blog

recent posts