获取自定义类型的Date()
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了获取自定义类型的Date()相关的知识,希望对你有一定的参考价值。
我有一个服务器API,它以两种不同格式提供JSON日期-一个结构嵌套在另一个结构中。
我的Swift应用程序提取操作使用Swift Codable来解码JSON,因此我需要添加一些特殊处理以允许对两种自定义日期格式进行解码。
很方便,我发现此excellent guide可在一个结构中处理不同的格式。
struct FirstModel: Codable, Identifiable
var id: Int?
let second: SecondModel
let date: CustomDate<First>
...
struct SecondModel: Codable, Identifiable
var id: Int?
let date: CustomDate<Second>
...
日期格式符定义如下,
struct CustomDate<E:HasDateFormatter>: Codable
let value: Date
init(from decoder: Decoder) throws
let container = try decoder.singleValueContainer()
let text = try container.decode(String.self)
guard let date = E.dateFormatter.date(from: text) else
throw CustomDateError.general
self.value = date
enum CustomDateError: Error
case general
struct First: HasDateFormatter
static var dateFormatter: DateFormatter
let dateFormatter = DateFormatter()
dateFormatter.locale = Locale.init(identifier: Constants.localeUK)
dateFormatter.dateFormat = "E, d MMM yyyy HH:mm zzz"
return dateFormatter
struct Second: HasDateFormatter
static var dateFormatter: DateFormatter
let dateFormatter = DateFormatter()
dateFormatter.locale = Locale.init(identifier: Constants.localeUK)
dateFormatter.dateFormat = "yyyy-MM-dd"
return dateFormatter
这一切都很好。
我的问题在我想创建一个随后要编码的对象时开始。
我什至无法初始化结构,
let first = FirstModel(id: nil, date: Date())
编译器给出错误,
无法将'date'类型的值转换为'date'参数的预期参数类型'CustomDate'。
我知道CustomDate(xxx)是DateFormatter,所以不是Date类型,但是我什至不知道从哪里开始获取该'type'的新Date对象。请有人帮助以Swift编译器接受的方式传递当前日期的语法。谢谢。
PS。我也怀疑我在某个时候需要一个“设置”编码器,对吧?
UPDATE
按照下面的Joakim的建议,加上我尝试的编译器的建议的Fix,
let date = try! CustomDate<First>(from: Date() as! Decoder)
...可以编译,但是在运行时崩溃,并显示错误,
无法将类型'Foundation.Date'的值转换为'Swift.Decoder'。
您可以创建自定义解码策略,以防失败时返回第二dateFormat。如果您需要按照相同的规则对自定义结构进行编码,则还需要提供自定义编码方法:
首先创建您的DateFormatters
extension Formatter
static let customUK: DateFormatter =
let formatter = DateFormatter()
formatter.calendar = Calendar(identifier: .iso8601)
formatter.locale = Locale(identifier: "en_UK")
formatter.dateFormat = "E, d MMM yyyy HH:mm zzz"
return formatter
()
static let yyyyMMdd: DateFormatter =
let formatter = DateFormatter()
formatter.calendar = Calendar(identifier: .iso8601)
formatter.locale = Locale(identifier: "en_UK")
formatter.dateFormat = "yyyy-MM-dd"
return formatter
()
然后是您的自定义日期解码策略
extension JSONDecoder.DateDecodingStrategy
static let customUK = custom
let container = try $0.singleValueContainer()
let string = try container.decode(String.self)
guard
let date = Formatter.customUK.date(from: string) ??
Formatter.yyyyMMdd.date(from: string) else
throw DecodingError.dataCorruptedError(in: container, debugDescription: "Invalid date: \(string)")
return date
以及您的自定义编码策略
extension JSONEncoder.DateEncodingStrategy
static let customUK = custom
var container = $1.singleValueContainer()
try container.encode(Formatter.customUK.string(from: $0))
如果需要确保按照原始日期格式对子结构进行编码,则需要为其提供自己的编码方法:
struct First: Codable
var id: Int?
let second: Second
let date: Date
init(id: Int?, date: Date = Date(), second: Second)
self.id = id
self.date = date
self.second = second
struct Second: Decodable
var id: Int?
let date: Date
init(id: Int?, date: Date = Date())
self.id = id
self.date = date
extension Second: Encodable
func encode(to encoder: Encoder) throws
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(id, forKey: .id)
try container.encode(Formatter.yyyyMMdd.string(for: date), forKey: .date)
游乐场测试:
let first = First(id: 1, second: .init(id: 2))
let encoder = JSONEncoder()
encoder.dateEncodingStrategy = .customUK
let data = try! encoder.encode(first)
print(String(data: data, encoding: .utf8)!) // "id":1,"second":"id":2,"date":"2020-06-02","date":"Tue, 2 Jun 2020 16:31 GMT-3"
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .customUK
let firstDecoded = try! decoder.decode(First.self, from: data)
print(firstDecoded) // "First(id: Optional(1), second: __lldb_expr_227.Second(id: Optional(2), date: 2020-06-02 03:00:00 +0000), date: 2020-06-02 19:38:00 +0000)\n"
以上是关于获取自定义类型的Date()的主要内容,如果未能解决你的问题,请参考以下文章