Swift 4 introduced the Codable
protocol to decode/encode JSON objects. Codable
is tightly integrated into the Swift toolchain. It is widely used on client-side and server-side Swift.
Sometimes, we meet challenges that require us to customize how we use Codable
to suit different advanced scenarios. Here are three hard challenges I’ve met when using Codable
and my clean code solutions.
Consider a hypothetical API that sometimes returns a String
and sometimes returns an Int
for the key id
:
[
{
"id": "XA134RRW",
"name": "Bob"
},
{
"id": 3003,
"name": "John"
}
MultipleTypes.json by Eric Yang
The most common and straightforward solution is using an Enum to map to the different cases. Do we have the clean code solution to avoid the boilerplate rawValue
it introduces?
To reduce the boilerplate and make clean code, I’m using the PropertyWrapper
:
// MARk: LosslessStringCodable
public typealias LosslessStringCodable = LosslessStringConvertible & Codable
// MARK: DynamicDecoder
public struct DynamicCoder<T: LosslessStringCodable> {
public static func decode(from decoder: Decoder) throws -> T? {
do {
return try T(from: decoder)
} catch {
// Handle different types for the same key error
func decode<T: LosslessStringCodable>(_: T.Type) -> (Decoder) -> LosslessStringCodable? {
return { try? T.init(from: $0) }
}
let types: [(Decoder) -> LosslessStringCodable?] = [
decode(String.self),
decode(Bool.self),
decode(Int.self),
decode(Double.self)
]
guard let rawValue = types.lazy.compactMap({ $0(decoder) }).first,
let value = T.init("\(rawValue)") else {
return nil
}
return value
}
}
}
// MARK: CodableValue
@propertyWrapper
public struct CodableValue<T: LosslessStringCodable>: Codable {
public let wrappedValue: T
public init(wrappedValue: T) {
self.wrappedValue = wrappedValue
}
public init(from decoder: Decoder) throws {
let value: T = try DynamicCoder.decode(from: decoder)!
self.init(wrappedValue: value)
}
public func encode(to encoder: Encoder) throws {
var container = encoder.singleValueContainer()
try container.encode(wrappedValue)
}
}
#programming #ios #mobile #technology #swift