Taking Enums in Swift away from its Sweet Spot

Photo by Mae Mu on Unsplash

Unlike many other languages, Enums in swift are very powerful. But we usually limit the usage of enums for few spots such as custom error type and representing different states of object.

Enums is basic value type used very commonly in iOS development. In this article, we will use enums in some uncommon but plausible use cases.

Associated values are biggest asset of enums. It is good to keep in mind that we can overload the cases by varying associated values. Here is simple example:

enum Role {  case artist  case developer  case director  case custom(String)  case custom(name: String)}

Testing equality of two enum objects is as simple as confirming to Equatable. Testing equality with two cases is pretty straightforward. When associated values are involved, the comparison is case sensitive and looks for exact match.

enum Role: Equatable {   case artist   case developer   case director   case custom(String)   case custom(number: Int)   case custom(name: String)}var caseLeft = Role.custom("common man")var caseRight = Role.custom("common man")var caseRight2 = Role.custom("commonman")var caseRight3 = Role.custom(number: 4)/// test equalitycaseLeft == caseRight  //truecaseLeft == caseRight2  //falsecaseLeft == caseRight3  //false

Having array of enums in iOS development is unavoidable. We will be using contains and extend functionality of contains to ignore case sensitivity.

var cases: [Role] = [.artist,.developer,.custom("king"),.custom(name: "king")]cases.contains(.artist) // truecases.contains(.custom("King")) // false - case sensitive

Here is implementation of containsCaseInsesitive

extension Array { func containsCaseInsensitive(character: Role) -> Bool where Element 
== Role {
switch character { case .custom(let str): var res = false for i in self { switch i { case .custom(let str2): res = (str.lowercased() == str2.lowercased()) if res == true { return res } default: continue } } return res default: return self.contains(character) } }}

Let us put the extension in action

cases.containsCaseInsensitive(character: .custom("King")) //true

While implementing above logic of containsCaseInsensitive, I encountered kind of weird thing. When you run above code in flow, you will not get expected result. You need to remove following cases from enum or re-arrange.

case custom(number: Int)
case
custom(name: String)
or enum Role: Equatable { case artist case developer case director case custom(number: Int) case custom(name: String) case custom(String)
}

This is weird in first look. But when we look deeper, compiler might be trying to match cases in order of top — down. In the process it might saw overloaded cases after match and went to default. But after re-arrangement, the perfect one is the last one in queue, so matches the condition. This is just one possible theory I am having.

Enums are Raw Representable if they have no associated values. Following is small example.

/// Compare Enums and Sort themenum OrderedValue: Int {  case order1 = 1  case order2}extension OrderedValue: Comparable { static func < (lhs: OrderedValue, rhs: OrderedValue) -> Bool {  lhs.rawValue < rhs.rawValue }
}
var compareTestArray: [OrderedValue] = [.order1,.order2,.order1]compareTestArray.sort(by: {$0<$1})compareTestArray // [order1, order1, order2]

Raw Representable values are values that can be re-constructed. With associated values which are dynamic it is not possible to re-construct.

let value = OrderedValue.order1OrderedValue(rawValue: value.rawValue)// This kind of reconstruction is not possible for enum with associated values because of their dynamic behaviour

This is very common topic with a lot of answers available in internet. Enum is generally used in scenario where there are different states possible for a problem in the use case.

enum fruit {  func eat() {    print("eaten")  }  case apple
case orange
}fruit.apple.eat()

Though we can make use of static in struct, a lot of code is involved. When you design enum with associated values and raw values, try using struct instead.

Thanks for reading :))

Love playing with data