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: SomeTypeFor 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.