1

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を変更するために拡張しようとしました。Datedecode(_: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 ソース コードの呼び出しをたどってみましたが、呼び出しがないようです。typeMismatchDoubleencode(to:)DatedecodeDate.init(from:Decoder)

だから私は疑問に思っています、Dateこの種の拡張機能を介して型がデコードされる方法を変更することは可能ですか? Dateすべての単一モデルでカスタム デコードを複製する唯一のオプションはありますか? いったい何を呼ぶのinit(from:Decoder)

4

1 に答える 1