Date.init(from:Decoder)
サーバーから渡されたさまざまな形式を処理するために、の機能を拡張しようとしています。日付が文字列としてエンコードされる場合もあれば、その文字列が辞書にネストされる場合もあります。Swift のソースによると、次のDate
ようにデコード/エンコードされます。
extension Date : Codable {
public init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
let timestamp = try container.decode(Double.self)
self.init(timeIntervalSinceReferenceDate: timestamp)
}
public func encode(to encoder: Encoder) throws {
var container = encoder.singleValueContainer()
try container.encode(self.timeIntervalSinceReferenceDate)
}
}
そこで、次のようにその機能を拡張しようとしました。
public extension Date {
private enum CodingKeys: String, CodingKey {
case datetime
}
public init(from decoder: Decoder) throws {
let dateString: String
if let container = try? decoder.container(keyedBy: CodingKeys.self) {
dateString = try container.decode(String.self, forKey: .datetime)
} else if let string = try? decoder.singleValueContainer().decode(String.self) {
dateString = string
} else {
let timestamp = try decoder.singleValueContainer().decode(Double.self)
self.init(timeIntervalSinceReferenceDate: timestamp)
return
}
if let date = Utils.date(from: dateString) {
self.init(timeIntervalSinceReferenceDate: date.timeIntervalSinceReferenceDate)
} else if let date = Utils.date(from: dateString, with: "yyyy-MM-dd") {
self.init(timeIntervalSinceReferenceDate: date.timeIntervalSinceReferenceDate)
} else {
let context = DecodingError.Context(codingPath: [], debugDescription: "Date format was unparseable.")
throw DecodingError.dataCorrupted(context)
}
}
}
ただし、この関数は呼び出されません。次に、次のようにデコードKeyedDecodingContainer
を変更するために拡張しようとしました。Date
decode(_:forKey)
extension KeyedDecodingContainer {
private enum TimeCodingKeys: String, CodingKey {
case datetime
}
func decode(_ type: Date.Type, forKey key: K) throws -> Date {
let dateString: String
if let timeContainer = try? self.nestedContainer(keyedBy: TimeCodingKeys.self, forKey: key) {
dateString = try timeContainer.decode(String.self, forKey: .datetime)
} else if let string = try? self.decode(String.self, forKey: key) {
dateString = string
} else {
let value = try self.decode(Double.self, forKey: key)
return Date(timeIntervalSinceReferenceDate: value)
}
if let date = Utils.date(from: dateString) {
return date
} else if let date = Utils.date(from: dateString, with: Globals.standardDateFormat) {
return date
} else {
let context = DecodingError.Context(codingPath: [], debugDescription: "Date format was not parseable.")
throw DecodingError.dataCorrupted(context)
}
}
}
ただし、 をDate
呼び出してエンコードした a をデコードするためにこれを呼び出すと、データが ではないというエラーが表示container.encode(date, forKey: .date)
されます。関数 forは Double を明示的にエンコードするため、何が起こっているのか完全に困惑しています。Swift ソース コードの呼び出しをたどってみましたが、呼び出しがないようです。typeMismatch
Double
encode(to:)
Date
decode
Date.init(from:Decoder)
だから私は疑問に思っています、Date
この種の拡張機能を介して型がデコードされる方法を変更することは可能ですか? Date
すべての単一モデルでカスタム デコードを複製する唯一のオプションはありますか? いったい何を呼ぶのinit(from:Decoder)
?