RT

Codable UIColor via property wrapper

We can add Codable support to UIColor with the help of a property wrapper. The following property wrapper allows us to encode and decode UIColor values as hex strings:

import UIKit
import ColorToolbox

@propertyWrapper
struct HexCodableColor: Codable {
    var wrappedValue: UIColor

    init(wrappedValue: UIColor) {
        self.wrappedValue = wrappedValue
    }

    init(from decoder: Decoder) throws {
        let container = try decoder.singleValueContainer()
        let hexString = try container.decode(String.self)

        guard let color = UIColor(hex: hexString) else {
            throw DecodingError.dataCorruptedError(
                in: container,
                debugDescription: "The value is not a valid hex color"
            )
        }

        wrappedValue = color
    }

    func encode(to encoder: Encoder) throws {
        var container = encoder.singleValueContainer()
        try container.encode(wrappedValue.toHex())
    }
}

The property wrapper uses the init?(hex:) and toHex() extensions from ColorToolbox.

Usage

Apply the wrapper to a UIColor property in a Codable struct/class:

struct MyModel: Codable {
    // ...
    @HexCodableColor var color: UIColor
}

Now we can encode/decode the struct the same way we would with any other Codable type:

let model = MyModel(color: .red)

let encoder = JSONEncoder()
let data = try encoder.encode(model) // -> {"color":"#FF0000"}