2

I have an array of strings that a returned from an API. These strings are a list of products available.

I would like to use an enum in my app to represent this data. I am unsure if this is possible however.

enum Products: String {
    case music
    case cars
    case sport
}

An example array I receive could be ["music", "cars"]

This is part of a struct that would be

struct CustomerState: Codable {
    var products = [Product]()
}

I was imaging I could map of the array and perhaps compare raw values, however I cannot work out how to do this or if this is the correct / possible approach.

2
  • Check this out Commented Feb 18, 2019 at 7:41
  • 1
    Simply specifing that Products conforms to Codable should do the trick. Commented Feb 18, 2019 at 7:43

2 Answers 2

3

I suppose you have json like this

let data = Data("""
{
"products" : [ "music", "cars" ]
}
""".utf8)

then you can just implement Codable to your enum

struct CustomerState: Codable {
    var products = [Products]()
}

enum Products: String, Codable {
    case music
    case cars
    case sport
}

and then you can decode Data

do {
    let decoded = try JSONDecoder().decode(CustomerState.self, from: data)
    //print(decoded.products[0])
} catch { print(error) }

Alternatively, if json always doesn't have to contains just declared enum cases, you can create custom initializer with decoder which decodes string array and then tries to create enum values from these strings. If case for this raw value doesn't exist, it isn't appended

struct CustomerState: Decodable {

    var products = [Products]()

    enum CodingKeys: String, CodingKey {
        case products
    }

    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        let products = try container.decode([String].self, forKey: .products)
        self.products = products.compactMap { Products(rawValue: $0) }
    }

}
Sign up to request clarification or add additional context in comments.

2 Comments

It's worth noting that if you get an unexpected value in your API response, entire decoding will fail.
As a confirmation to @Losiowaty's comment, the array in the json is ["music", "cheese"] you will get an error of "Cannot initialize Products from invalid String value cheese".
2

You could achieve it by mapping the current array of strings to an array of enum cases based on their rawValues:

let array = ["music", "cars", "tomato"]
let arrayEnum = array.map { Products(rawValue: $0) }

At this point, keep in mind that arrayEnum is [Products?] containing 3 elements because mapping "tomato" string gives nil. What you could do for getting rid of nils is to use the compactMap:

let array = ["music", "cars", "tomato"]

let arrayEnum = array.compactMap { Products(rawValue: $0) }
print(arrayEnum)

Now arrayEnum contains only two elements without the nil one.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.