Subscribe to my newsletter and never miss the upcoming articles

Creating your own custom RawRepresentable Enum in Swift

RawRepresentable Enum in Swift guide for beginners enum

Hallo vrienden en familie, Leo hier. Today we will explore how to do your own RawRepresentable Enum in Swift.

I like to ask iOS developers what is their favorite Swift feature. It is very common that the answer is Enums and I understand why. An enumeration defines a standard type for a group of related data and enables you to work with those values in a type-safe way throughout your code.

Enum types are value types and therefore and pass around by value, therefore they are intrinsically thread-safe. Enums are very useful to parse and give meaning to closed-range values with a well-defined meaning. For example, You can have an enum named RealState that has types that are house, apartment, condo, townhouse, etc.

You can give any meaning to enums. Enums have a brilliant power of indirection, which enables an enum to reference itself, enabling you to create binary trees with them. Enums have the feature to have associated values and also raw values and raw values are what will explore today.

No more talking, let’s code! But first…  

 

Painting of The Day

The painting I chose today is an 1823 art piece called Seller of cooked goods and tripe, Seller of raw goods by Saverio della Gatta.

Saverio Della Gatta was an Italian Old Masters artist who was born in 1758. His work has been offered at auction multiple times, with realized prices ranging from 485 USD to 194,448 USD, depending on the size and medium of the artwork. Since 1998 the record price for this artist at auction is 194,448 USD for NAPLES, VIEW OF THE PALAZZO REALE DI PORTICI; NAPLES, VIEW OF THE PORT OF PORTICI, sold at Sotheby’s Paris in 2009.

I chose the painting because of the seller of raw goods in on the right-side of the picture. Today we will mess with a lot of raw stuff.  

 

The Problem – Custom RawRepresentable Enum in Swift

I want to create a custom implementation of RawRepresentable for my enum

The Swift language does a lot for us. For example, if you add a Raw Value to the enum it auto-generates the raw representable protocol for you. Check the example below:  

enum RealState: String {
    case house
    case apartment
    case vila
    case townhouse
}

let realStateInvalid = RealState(rawValue: "lol")
let realStateValid = RealState(rawValue: "house") ?? .house

print(realStateInvalid?.rawValue)
print(realStateValid.rawValue)

In the example above, when you add a String in the enum declaration it means that all the enum is now conforming to RawRepresentable using as associated type the String struct. That conformance gives us two things: one initializer and one variable. And you can see both in the code above in the “RealState(rawValue:_)” and in the “realStateValid.rawValue“.

Also remember that RawRepresentable can be anything because is a generic declaration in the protocol, so your imagination is the limit for conformance. Every time that you need all values to be automatically parsed into a type you can use the initialization as above… Unless… You have associated types with your cases.

Check the example below:

enum Media: String {
    case video(String) // error
    case article // this is ok
    case photo(name:String, date: Date) // error again
}

But why? Do you remember that we explained that Swift language does a lot for us? This is one of the cases in which the compiler can’t infer the types for us because as the raw values are always the same for each case, it can’t infer what would be a raw value for cases that have values associated because the fact it doesn’t know. Anything it would return would be a wild guess. The good thing is that we can implement the RawRepresentable to solve this kind of problem!

Let’s check how.  

 

How to implement custom RawRepresentable to Enum?

In the example above let’s add the RawRepresentable conformance. We still want that the raw value is a String but in your case, you could choose anything you want to be the raw value of your types.

Check the code below.

enum Media {
    case video(String)
    case article(Int)
    case photo(name:String,date: Date)
}

extension Media: RawRepresentable {
    init?(rawValue: String) { // here we are saying to the compiler that the raw value will be type String
        if !rawValue.matches(of: try! Regex("video")).isEmpty {
            self = .video(rawValue+" video_default")
        } else if !rawValue.matches(of: try! Regex("article")).isEmpty {
            self = .article(rawValue.count)
        } else if !rawValue.matches(of: try! Regex("photo")).isEmpty {
            self = .photo(name: rawValue, date: Date())
        } else {
            return nil
        }
    }
    
    var rawValue: String { // here we are saying to the compiler that the raw value will be type String 
        switch self {
        case .video(let videoName):
            return "The video name is \(videoName)"
        case .article(let articleNumber):
            return "The article number is \(articleNumber)"
        case .photo(name: let name, date: let date):
            return "Photo named: \(name), with date: \(date)"
        }
    }
}

We had to implement both of the structures required by the RawRepresentable protocol, the optional init and the rawValue variable. And you can do whatever you want, if you wanted a raw value of another type, for example, Int you could do it.

Now you can test like this:

let medias = [Media(rawValue: "video_MikeSummer"),
              Media(rawValue: "article_PepijnWeMissYou"),
              Media(rawValue: "photo_AlanMultiplatform"),
              Media(rawValue: "???????")]

for media in medias {
    switch media {
    case .video(let videoName):
        print("The raw value is:[\(media!.rawValue)] and the associated value is [\(videoName)]")
    case .article(let articleNumber):
        print("The raw value is:[\(media!.rawValue)] and the associated value is [\(articleNumber)]")
    case .photo(name: let name, date: let date):
        print("The raw value is:[\(media!.rawValue)] and the associated value are [\(name), \(date)]")
    case .none:
        print("media is nil")
    }
}

And that’s all for today!  

 

Explore Other Swift Topics

Exploring APIs in Swift is important to increase your toolbox and mind as a developer. One important magic that is available in the language is the Mirror API, that guess what? It enables reflection techniques and you can learn how to do that in Swift with this article.

When I started my career the last step in my studies was about iOS tooling and architectures. This was a conscious decision because I want to have my foundations really set before starting an adventure on what the iOS community was using to organize the code. Check all the tips about how to begin your studies in iOS architecture and tooling in this article!  

 

Summary – Custom RawRepresentable Enum in Swift

Today we studied how to implement your custom RawRepresentable Enum in Swift and solve the problem with that conformance when you have associated types.

Fellow developers, that’s all. I hope you liked reading this article as much as I enjoyed writing it. If you want to support this blog you can Buy Me a Coffee or just leave a comment saying hello. You can also sponsor posts! You can reach me on LinkedIn, or Twitter or send me an e-mail through the contact page.

Thanks for the reading and… That’s all folks. Image Credit: Wikiart

Share this post:

Related posts

Sponsor