I use property wrappers to specify the date format I want to use for the Decodable
protocol. However, when I try to use them in a custom init(from decoder: Decoder)
, it starts giving me an error.
The question is: How can I make it respect the property wrappers?
I'm expect decode(Date.self,...
is where the issue is, but I haven't found a way to insert a property wrapper there.
As an example, here are 2 almost identical structs. The Ok
struct decodes perfectly, while NotOk
throws an error, which is what I'm looking to fix.
struct Ok: Decodable {
@LADateWithoutT var date: Date
enum CodingKeys: String, CodingKey { case date }
}
struct NotOk: Decodable {
@LADateWithoutT var date: Date
enum CodingKeys: String, CodingKey { case date }
public init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
date = try values.decode(Date.self, forKey: .date) // <- ISSUE HERE
}
}
let json = #"{"date":"2021-05-10 12:14:28Z"}"#.data(using: .utf8)!
let decoder = JSONDecoder()
do {
let _ = try decoder.decode(Ok.self, from: json) // <- WORKS FINE
} catch { print("OK: \(error)") }
do {
let _ = try decoder.decode(NotOk.self, from: json) // <- THROWS AN ERROR
} catch { print("NotOK: \(error)") }
Property wrapper
import Foundation
/// Wrapper for dates formatted as `"YYYY-MM-DD HH:mm:ssZ"`.
@propertyWrapper
public struct LADateWithoutT: Codable {
static internal var formatter: DateFormatter {
let formatter = DateFormatter()
formatter.dateFormat = "YYYY-MM-DD HH:mm:ssZ"
return formatter
}
public var wrappedValue: Date
public init(wrappedValue: Date) {
self.wrappedValue = wrappedValue
}
public init(from decoder: Decoder) throws {
let strValue = try decoder.singleValueContainer().decode(String.self)
guard let date = LADateWithoutT.formatter.date(from: strValue) else {
throw LAClientError.dateIsNil
}
self.wrappedValue = date
}
public func encode(to encoder: Encoder) throws {
let strValue = LADateWithoutT.formatter.string(from: wrappedValue)
try strValue.encode(to: encoder)
}
}