OOZOU
Get in Touch
Back to Blog

Enum & custom type from primitive JSON type

Learn two techniques in Codable

December 18, 2018
4 min read
Enum & custom type from primitive JSON type

Today we are going to learn how two cases that you might need to do when dealing with Codable. Parsing Enum and Parsing custom type from a primitive type like string.

Enum

If your enum has a raw value that can be represented as Int or String (which I think that should cover most cases). We can make enum Codable by assigning a raw value to it.

Let’s say you have JSON object like this:

{"name": "iOS developer", "status": "open"}
lang-json

You can create Swift struct like this:

<pre>struct Job: Codable {
  enum Status: String, Codable {
    case open
    case close
  }
  let name: String
  let status: Status
}
lang-swift

If you have enum which isn’t String or Int representable you can still make it conform to Codable as long as that raw value is Codable.

Custom type from a primitive type

If you have a custom type that can be derived from basic JSON type, for example, you have an object with image sending as base64 encoded string:

{
  "name": "XXX",
  "image": "data:image/png;base64,iVBORw0KGgo......."
}
lang-json

Since UIImage doesn’t conform to Codable and we can’t conform it with an extension, we have 2 ways to handle this:

  1. Create another wrapper class around this image.
struct Base64ImageWrapper: Codable {
    let image: UIImage

    public init(from decoder: Decoder) throws {
        let container = try decoder.singleValueContainer()        
        let base64String = try container.decode(String.self)        
        let components = base64String.split(separator: ",")        
        if components.count != 2 {
            throw DecodingError.dataCorruptedError(in: container, debugDescription: "Wrong data format")
        }

        let dataString = String(components[1])

        if let dataDecoded = Data(base64Encoded: dataString, options: .ignoreUnknownCharacters),
            let image = UIImage(data: dataDecoded) {
            self.image = image
        } else {
            throw DecodingError.dataCorruptedError(in: container, debugDescription: "Can't initialize image from data string")
        }
    }

    public func encode(to encoder: Encoder) throws {
        var container = encoder.singleValueContainer()
        let data = image.jpegData(compressionQuality: 1)
        let prefix = "data:image/jpeg;base64,"
        guard let base64String = data?.base64EncodedString(options: .lineLength64Characters) else {
            throw EncodingError.invalidValue(image, EncodingError.Context(codingPath: [], debugDescription: "Can't encode image to base64 string."))
        }

        try container.encode(prefix + base64String)
    }
}
lang-swift

The code above should be familiar to you with one key take away. Instead of:

let values = try decoder.container(keyedBy: CodingKeys.self)
lang-swift

We use:

let container = try decoder.singleValueContainer()
lang-swift

since we are dealing with one primitive value, base64 string, in this case. Then we can use this wrapper like this:

<pre>struct ModelUsingImageWrapper: Codable {
  let name: String
  let image: Base64ImageWrapper
}
lang-swift
  1. Add custom encode/decode for UIImage in KeyedEncodingContainer:
extension KeyedEncodingContainer {

    mutating func encode(_ value: UIImage,
                         forKey key: KeyedEncodingContainer.Key) throws {

        let imageData = value.jpegData(compressionQuality: 1)
        let prefix = "data:image/jpeg;base64,"        

        guard let base64String = imageData?.base64EncodedString(options: .lineLength64Characters) else {
            throw EncodingError.invalidValue(value, EncodingError.Context(codingPath: codingPath, debugDescription: "Can't encode image to base64 string."))
        }

        try encode(prefix + base64String, forKey: key)
    }

}

extension KeyedDecodingContainer {

    public func decode(_ type: UIImage.Type, forKey key: KeyedDecodingContainer.Key) throws -> UIImage {
        let base64String = try decode(String.self, forKey: key)

        // data:image/svg+xml;base64,PD.....
        let components = base64String.split(separator: ",")

        if components.count != 2 {
            throw DecodingError.typeMismatch(type, DecodingError.Context(codingPath: codingPath, debugDescription: "Unsupported format"))
        }

        let dataString = String(components[1])
        if let dataDecoded = Data(base64Encoded: dataString, options: .ignoreUnknownCharacters), let image = UIImage(data: dataDecoded) {
            return image
        } else {
            throw DecodingError.typeMismatch(type, DecodingError.Context(codingPath: codingPath, debugDescription: "Unsupported format"))
        }
    }

}
lang-swift

And use this with explicit encode and decode.

struct ModelUsingKeyedEncodingContainer: Codable {
  let name: String
  let image: UIImage<pre>  enum CodingKeys: String, CodingKey {
    case name
    case image
  }
  public init(from decoder: Decoder) throws {
    let container = try decoder.container(keyedBy: CodingKeys.self)
    name = try container.decode(String.self, forKey: .name)
    image = try container.decode(UIImage.self, forKey: .image)
  }
  public func encode(to encoder: Encoder) throws {
    var container = encoder.container(keyedBy: CodingKeys.self)
    try container.encode(name, forKey: .name)
    try container.encode(image, forKey: .image)
  }
}
lang-swift

These 2 approaches should suffice for most of your use cases.

Related Articles

How Can I Design a Software: A Beginners Guide for Business Owners

How Can I Design a Software: A Beginners Guide for Business Owners

Designing software is an exciting yet complex process that involves creativity, logical thinking, and problem-solving skills.

Read More →
The Future of Edge Computing: What Businesses Need to Know

The Future of Edge Computing: What Businesses Need to Know

The digital landscape is evolving rapidly, and businesses must adapt to keep up with rising demands for speed, efficiency, and real-time processing.

Read More →
The Future of Retail: AI, AR, and Digital Transformation Trends

The Future of Retail: AI, AR, and Digital Transformation Trends

Retail is evolving at an unprecedented pace, driven by AI (Artificial Intelligence), AR (Augmented Reality), and digital transformation technologies, revolutionizing the retail industry. Traditional brick-and-mortar stores are no longer just about selling products—they are becoming smart, interactiv

Read More →

Have a Project in Mind?

Let's discuss how we can help bring your ideas to life with our expertise in web and mobile development.

Start a Conversationhello@oozou.com
OOZOU Logo

Bangkok · Singapore · Hong Kong

X
Facebook
Instagram
LinkedIn

Services

  • Web Development
  • AI Agents & Generative AI
  • Mobile App Development
  • Data Analytics & Engineering
  • UI/UX & Product Design
  • Digital Transformation

Company

  • About Us
  • Careers
  • Blog
  • Case Studies
  • Today I Learned
  • Contact

More

  • Industries
  • Partner Network
© 2026 OOZOU. All rights reserved.
Privacy PolicyCode of ConductABAC Policy