Я пытался использовать пользовательскую стратегию даты в json декодировании с использованием Codable
, как описано в { ссылка }. Вот упрощенный код реализации:
public extension Formatter {
static let iso8601: DateFormatter = {
let formatter = DateFormatter()
formatter.calendar = Calendar(identifier: .iso8601)
formatter.locale = Locale(identifier: "en_US_POSIX")
formatter.timeZone = TimeZone(secondsFromGMT: 0)
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSXXXXX"
return formatter
}()
}
public extension Date {
var iso8601: String {
return Formatter.iso8601.string(from: self)
}
}
public extension JSONDecoder.DateDecodingStrategy {
static let iso8601withFractionalSeconds = custom {
let container = try $0.singleValueContainer()
let string = try container.decode(String.self)
guard let date = Formatter.iso8601.date(from: string) else {
throw DecodingError.dataCorruptedError(in: container,
debugDescription: "Invalid date: " + string)
}
return date
}
}
public extension JSONEncoder.DateEncodingStrategy {
static let iso8601withFractionalSeconds = custom {
var container = $1.singleValueContainer()
try container.encode(Formatter.iso8601.string(from: $0))
}
}
Однако, когда дело доходит до модульного тестирования, оно терпит неудачу, хотя сообщение об ошибке показывает равное значение, используемое description
методом даты:
func test_jsonCodable_iso8601() {
let dates = [Date()] // ["Feb 9, 2020 at 12:55:24 PM"]
let encoder = JSONEncoder()
encoder.dateEncodingStrategy = .iso8601withFractionalSeconds
let data = try! encoder.encode(dates)
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .iso8601withFractionalSeconds
let decodedDates = try! decoder.decode([Date].self, from: data) // ["Feb 9, 2020 at 12:55:24 PM"]
XCTAssertEqual(dates, decodedDates)
// fails with error message: [2020-02-09 12:55:24 +0000]") is not equal to ("[2020-02-09 12:55:24 +0000]"
}
Есть ли у вас какие-либо идеи о том, в чем заключается проблема и как мы можем ее решить?
Кстати, фактический декодируемый объект - это следующий, где publishedAt
имеет тип даты:
public struct NewsItem: Equatable {
public let id: UUID
public let author: String
public let title: String
public let description: String
public let urlToImage: URL?
public let publishedAt: Date
public let content: String
public init(id: UUID,
author: String,
title: String,
description: String,
urlToImage: URL?,
publishedAt: Date,
content: String) {
self.id = id
self.author = author
self.title = title
self.description = description
self.urlToImage = urlToImage
self.publishedAt = publishedAt
self.content = content
}
}
extension NewsItem: Decodable {}