swiftenums

How do I make an enum Decodable in Swift?


enum PostType: Decodable {

    init(from decoder: Decoder) throws {

        // What do i put here?
    }

    case Image
    enum CodingKeys: String, CodingKey {
        case image
    }
}

What do i put to complete this? Also, lets say i changed the case to this:

case image(value: Int)

How do I make this conform to Decodable?

Here is my full code (which does not work)

let jsonData = """
{
    "count": 4
}
""".data(using: .utf8)!
        
        do {
            let decoder = JSONDecoder()
            let response = try decoder.decode(PostType.self, from: jsonData)
            
            print(response)
        } catch {
            print(error)
        }
    }
}

enum PostType: Int, Codable {
    case count = 4
}

Also, how will it handle an enum like this?

enum PostType: Decodable {
    case count(number: Int)
}

Solution

  • It's pretty easy, just use String or Int raw values which are implicitly assigned.

    enum PostType: Int, Codable {
        case image, blob
    }
    

    image is encoded to 0 and blob to 1

    Or

    enum PostType: String, Codable {
        case image, blob
    }
    

    image is encoded to "image" and blob to "blob"


    This is a simple example how to use it:

    enum PostType : Int, Codable {
        case count = 4
    }
    
    struct Post : Codable {
        var type : PostType
    }
    
    let jsonString = "{\"type\": 4}"
    
    let jsonData = Data(jsonString.utf8)
    
    do {
        let decoded = try JSONDecoder().decode(Post.self, from: jsonData)
        print("decoded:", decoded.type)
    } catch {
        print(error)
    }
    

    Update

    In iOS 13.3+ and macOS 15.1+ it's allowed to en-/decode fragments – single JSON values which are not wrapped in a collection type

    let jsonString = "4"
    
    let jsonData = Data(jsonString.utf8)
    do {
        let decoded = try JSONDecoder().decode(PostType.self, from: jsonData)
        print("decoded:", decoded) // -> decoded: count
    } catch {
        print(error)
    }
    

    In Swift 5.5+ it's even possible to en-/decode enums with associated values without any extra code. The values are mapped to a dictionary and a parameter label must be specified for each associated value

    enum Rotation: Codable {
        case zAxis(angle: Double, speed: Int)
    }
    
    let jsonString = #"{"zAxis":{"angle":90,"speed":5}}"#
    
    let jsonData = Data(jsonString.utf8)
    do {
        let decoded = try JSONDecoder().decode(Rotation.self, from: jsonData)
        print("decoded:", decoded)
    } catch {
        print(error)
    }