CodableProperty is a framework written in Swift that works along with the build in Codable
protocol. Uses the new propertyWrapper
feature of Swift 5.1 to make type transformation easier.
To run the example project, clone the repo, and run pod install
from the Example directory first.
- iOS 8.0+ / macOS 10.9+ / tvOS 9.0+ / watchOS 2.0+
- Xcode 11+
- Swift 5.1+
To use CodableProperty
just implement CodableTransformer
protocol and use it inside your Codable
model like this:
@CodableProperty<CustomCodableTransformer> var someProperty: SomeType
For example if you have the following JSON:
{
"currency": "PLN",
"rates": {
"USD": 3.76,
"EUR": 4.24,
"SEK": 0.41
}
}
And you want to map it in a model like this:
struct CurrencyConversion {
var currency: String
var rates: [ExchangeRate]
}
struct ExchangeRate {
let currency: String
let rate: Double
}
You can transform the JSON type to your model type by implementing CodableTransformer
protocol:
struct RatesTransformer: CodableTransformer {
typealias Value = [ExchangeRate]
func value(from decoder: Decoder) throws -> Value {
let container = try decoder.singleValueContainer()
let dictionary = try container.decode([String: Double].self)
return dictionary.map { key, value in
ExchangeRate(currency: key, rate: value)
}
}
func encode(value: Value, to encoder: Encoder) throws {
var container = encoder.singleValueContainer()
let dictionary = value.reduce(into: [String: Double]()) { result, exchangeRate in
result[exchangeRate.currency] = exchangeRate.rate
}
try container.encode(dictionary)
}
}
And use it in your Codable
model like this:
struct CurrencyConversion: Codable {
var currency: String
@CodableProperty<RatesTransformer> var rates: [ExchangeRate]
}
struct ExchangeRate {
let currency: String
let rate: Double
}
If you model implements Decodable
protocol instead of Codable
you can specialize the type transformation only in decoding process by implementing DecodableTransformer
protocol:
struct RatesTransformer: DecodableTransformer {
typealias Value = [ExchangeRate]
func value(from decoder: Decoder) throws -> Value {
let container = try decoder.singleValueContainer()
let dictionary = try container.decode([String: Double].self)
return dictionary.map { key, value in
ExchangeRate(currency: key, rate: value)
}
}
}
And use it like this:
struct CurrencyConversion: Decodable {
var currency: String
@DecodableProperty<RatesTransformer> var rates: [ExchangeRate]
}
The same applies also to Encodable
models:
struct RatesTransformer: EncodableTransformer {
typealias Value = [ExchangeRate]
func encode(value: Value, to encoder: Encoder) throws {
var container = encoder.singleValueContainer()
let dictionary = value.reduce(into: [String: Double]()) { result, exchangeRate in
result[exchangeRate.currency] = exchangeRate.rate
}
try container.encode(dictionary)
}
}
struct CurrencyConversion: Encodable {
var currency: String
@EncodableProperty<RatesTransformer> var rates: [ExchangeRate]
}
- If you found a bug, open an issue.
- If you have a feature request, open an issue.
CodableProperty is available through CocoaPods. To install it, simply add the following line to your Podfile:
pod 'CodableProperty'
To add CodableProperty to a Swift Package Manager based project, add the following:
.package(url: "https://github.com/gcharita/CodableProperty.git", from: "1.0.0")
to the dependencies
value of your Package.swift
.
Special thanks to John Sundell. His example in this article inspired me to write this project.
CodableProperty is available under the MIT license. See the LICENSE file for more info.