Alexito's World

A world of coding 💻, by Alejandro Martinez

Swift enums and UISegmentedControl

2018/08/18: Swift 4.2 introduces automatic synthesis of enum values. Check out the new version of this post. 2016/09/29: Updated for Swift 3.

One of the most cool features in Swift are the super powered enums. I really like how the enums and the structs have more features that their C counterparts.

I've tried to use enums to fill a UISegmentedControl. I thought it will be cool to have automatically match the segmented control index with the enum, but I also want to fill the segmented control titles with the values of the enum (as Strings).

Honestly I thought that it will be more easy but (right now, and as far as I know) there are no way to iterate over the values of an enum without doing some manual stuff.

Maybe this would be posible in a future beta. Source

First of all, my example enum:

enum Size: Int { case S = 0 case M case L case XL }

What I've done is create a function that returns an array with all the values of the enum (note: __conversiondoesn't work anymore, see below):

static func allValues() -> [String] { return [S, M, L, XL].map({$0.description}) }

Two things to note here:

  • You can declare the function as static to make the function part of the enum, not part of a specific value. Like a class method.
  • This is the worse part, you need to fill this array manually.

I also created a static function that returns the total number of values. This is really useful if you need to use the enum in a data source protocol or something similar. In Objective-C I normally add a final value to the enum with the name count, but Swift forces you to define all the posible cases in a switch statement so I think that having the number of posible values in a function is better. In this case I can use the allValues() function to make things easier.

static func count() -> Int { return allValues().count }

This __conversion method doesn't work anymore, see next paragraph for a replacement

If you have read carefully you will have seen some strange thing in the allValues() method: is returning a [String]. But this is not posible by default, our enum is not a String. To accomplish this Swift give us a cool feature that allows us to convert our custom types into any other type.

func __conversion() -> String { switch self { case .S: return "S" case .M: return "M" case .L: return "L" case .XL: return "XL" } }

With this function you are allowing your enum to be converted to a String when needed. The bad part is that here we have another manual thing to do.

Since this magic method doesn't work anymore, we can now use CustomStringConvertible and implement the usual description method. And then use map to convert the enum values into strings.

public var description: String { switch self { case .S: return "S" case .M: return "M" case .L: return "L" case .XL: return "XL" } }

With all of this you now can do something like this:

let segmented = UISegmentedControl(items: Size.allValues()) ... Size.fromRaw(segmented.selectedSegmentIndex)

That's all. If anyone knows a better way to do it you know where find me.

Here's a playground.

If you liked this article please consider supporting me