ryanfrancesconi/spfk-raw-codable
A Swift macro that generates explicit `Codable` conformance for `RawRepresentable` enums.
Motivation
Swift's synthesized Codable for enums can fail under SwiftData's runtime decoder, which uses Key-Value Coding (KVC) to walk the property graph of composite attributes. When SwiftData encounters an enum stored in a composite struct, it needs the enum to handle its own serialization explicitly rather than relying on compiler-synthesized Codable. Without this, you get NSUnknownKeyException crashes at runtime.
@RawCodable eliminates the boilerplate of writing identical init(from:) / encode(to:) implementations on every RawRepresentable enum in your data model.
Usage
import RawCodable
@RawCodable
public enum BitDepthRule: String, Sendable {
case lessThanOrEqual
case any
}The macro expands to:
extension BitDepthRule: Codable {
public init(from decoder: any Decoder) throws {
let container = try decoder.singleValueContainer()
let rawValue = try container.decode(String.self)
guard let value = Self(rawValue: rawValue) else {
throw DecodingError.dataCorruptedError(
in: container,
debugDescription: "Unknown \(Self.self) raw value: \(rawValue)"
)
}
self = value
}
public func encode(to encoder: any Encoder) throws {
var container = encoder.singleValueContainer()
try container.encode(rawValue)
}
}Works with both String and Int raw values:
@RawCodable
public enum Priority: Int, Sendable {
case low = 0
case medium = 1
case high = 2
}Requirements
- Swift 6.2+
- macOS 13+
Installation
Add the package to your Package.swift:
dependencies: [
.package(url: "https://github.com/ryanfrancesconi/spfk-raw-codable", from: "1.0.0"),
]Then add RawCodable to your target's dependencies:
.target(
name: "MyTarget",
dependencies: [
.product(name: "RawCodable", package: "spfk-raw-codable"),
]
)License
Copyright Ryan Francesconi. All Rights Reserved.
Package Metadata
Repository: ryanfrancesconi/spfk-raw-codable
Default branch: main
README: README.md