可解码多个 DateDecodingStrategies
Decodable multiple DateDecodingStrategies
是否可以将多个 JSONDecoder.DateDecodingStrategy
添加到同一个 JSONDecoder
?
我有一个解码器:
struct Movie: Decodable {
enum CodingKeys: String, CodingKey {
case title = "display_title"
case mpaaRating = "mpaa_rating"
case criticsPick = "critics_pick"
case byline
case headline
case summaryShort = "summary_short"
case publicationDate = "publication_date"
case openingDate = "opening_date"
case dateUpdated = "date_updated"
case link
case multimedia
}
let title: String
let mpaaRating: String
let criticsPick: Int
let byline: String
let headline: String
let summaryShort: String
let publicationDate: Date
let openingDate: Date?
let updatedDate: Date
let link: MovieLink
let multimedia: MovieMultimedia
var image: UIImage?
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
try title = values.decode(String.self, forKey: .title)
try mpaaRating = values.decode(String.self, forKey: .mpaaRating)
try criticsPick = values.decode(Int.self, forKey: .criticsPick)
try byline = values.decode(String.self, forKey: .byline)
try headline = values.decode(String.self, forKey: .headline)
try summaryShort = values.decode(String.self, forKey: .summaryShort)
try openingDate = values.decodeIfPresent(Date.self, forKey: .openingDate)
try publicationDate = values.decode(Date.self, forKey: .publicationDate)
try updatedDate = values.decode(Date.self, forKey: .dateUpdated)
try link = values.decode(MovieLink.self, forKey: .link)
try multimedia = values.decode(MovieMultimedia.self, forKey: .multimedia)
}
mutating func loadImage(completion: @escaping (UIImage?, Error?) -> ()) {
URLSession.shared.dataTask(with: self.multimedia.src) { data, _, error in
DispatchQueue.main.async {
if let data = data {
let image = UIImage(data: data)
completion(image, error)
}
}
}.resume()
}
}
struct MovieLink: Decodable {
enum CodingKeys: String, CodingKey {
case type
case url
case suggestedLinkText = "suggested_link_text"
}
let type: String
let url: URL
let suggestedLinkText: String
}
struct MovieMultimedia: Decodable {
let type: String
let src: URL
let height: Int
let width: Int
}
现在我遇到了一个问题,因为 API 提供了不同的日期格式。对于 pulicaion_date、opening_date,使用以下模式 2017-10-10。
但是对于 date_updated 他们发送格式为 2017-10-10 12:21:02.
的数据
当我将 JSONDecoder
的 DateDecodingStrategy
设置为 .formatted(myDateFormatter) 时,它因 date_updated
而崩溃
解码器是这样调用的
let decoder = JSONDecoder()
let dateformatter = DateFormatter()
dateformatter.dateFormat = "yyyy-MM-dd"
decoder.dateDecodingStrategy = .formatted(dateformatter)
let movieList = try! decoder.decode(MovieList.self, from: data!)
并崩溃:
fatal error: 'try!' expression unexpectedly raised an error:
Swift.DecodingError.dataCorrupted(
Swift.DecodingError.Context(
codingPath: [
Test_App.MovieList.CodingKeys.movies,
Foundation.(_JSONKey in _12768CA107A31EF2DCE034FD75B541C9)(stringValue: "Index 0", intValue: Optional(0)),
Test_App.Movie.CodingKeys.dateUpdated
],
debugDescription: "Date string does not match format expected by formatter.",
underlyingError: nil)
)
您可以为此使用 DateDecodingStrategy.custom
选项。一个简短的例子:
let shortFormatter = DateFormatter()
let longFormatter = DateFormatter()
shortFormatter.dateFormat = "yyyy-MM-dd"
longFormatter.dateFormat = "yyyy-MM-dd hh:mm:ss"
func customDateFormatter(_ decoder: Decoder) throws -> Date {
let dateString = try decoder.singleValueContainer().decode(String.self)
let dateKey = decoder.codingPath.last as! Movie.CodingKeys
switch dateKey {
case .shortDate :
return shortFormatter.date(from: dateString)!
case .longDate :
return longFormatter.date(from: dateString)!
default:
fatalError("Unexpected date coding key: \(dateKey)")
}
}
我在 DateFormatter
函数之外 创建了两个实例 只是为了优化。因此,每次调用都不需要 recreate/configure 每个解码日期。
最后,使用我们在上面创建的函数设置 dateDecodingStrategy
:
let json =
"""
{
"name": "A Clockwork Orange",
"short_date": "2017-10-10",
"long_date": "2017-10-10 12:21:02"
}
""".data(using: .utf8)!
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .custom(customDateFormatter)
let movie = try! decoder.decode(Movie.self, from: json)
是否可以将多个 JSONDecoder.DateDecodingStrategy
添加到同一个 JSONDecoder
?
我有一个解码器:
struct Movie: Decodable {
enum CodingKeys: String, CodingKey {
case title = "display_title"
case mpaaRating = "mpaa_rating"
case criticsPick = "critics_pick"
case byline
case headline
case summaryShort = "summary_short"
case publicationDate = "publication_date"
case openingDate = "opening_date"
case dateUpdated = "date_updated"
case link
case multimedia
}
let title: String
let mpaaRating: String
let criticsPick: Int
let byline: String
let headline: String
let summaryShort: String
let publicationDate: Date
let openingDate: Date?
let updatedDate: Date
let link: MovieLink
let multimedia: MovieMultimedia
var image: UIImage?
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
try title = values.decode(String.self, forKey: .title)
try mpaaRating = values.decode(String.self, forKey: .mpaaRating)
try criticsPick = values.decode(Int.self, forKey: .criticsPick)
try byline = values.decode(String.self, forKey: .byline)
try headline = values.decode(String.self, forKey: .headline)
try summaryShort = values.decode(String.self, forKey: .summaryShort)
try openingDate = values.decodeIfPresent(Date.self, forKey: .openingDate)
try publicationDate = values.decode(Date.self, forKey: .publicationDate)
try updatedDate = values.decode(Date.self, forKey: .dateUpdated)
try link = values.decode(MovieLink.self, forKey: .link)
try multimedia = values.decode(MovieMultimedia.self, forKey: .multimedia)
}
mutating func loadImage(completion: @escaping (UIImage?, Error?) -> ()) {
URLSession.shared.dataTask(with: self.multimedia.src) { data, _, error in
DispatchQueue.main.async {
if let data = data {
let image = UIImage(data: data)
completion(image, error)
}
}
}.resume()
}
}
struct MovieLink: Decodable {
enum CodingKeys: String, CodingKey {
case type
case url
case suggestedLinkText = "suggested_link_text"
}
let type: String
let url: URL
let suggestedLinkText: String
}
struct MovieMultimedia: Decodable {
let type: String
let src: URL
let height: Int
let width: Int
}
现在我遇到了一个问题,因为 API 提供了不同的日期格式。对于 pulicaion_date、opening_date,使用以下模式 2017-10-10。
但是对于 date_updated 他们发送格式为 2017-10-10 12:21:02.
的数据当我将 JSONDecoder
的 DateDecodingStrategy
设置为 .formatted(myDateFormatter) 时,它因 date_updated
解码器是这样调用的
let decoder = JSONDecoder()
let dateformatter = DateFormatter()
dateformatter.dateFormat = "yyyy-MM-dd"
decoder.dateDecodingStrategy = .formatted(dateformatter)
let movieList = try! decoder.decode(MovieList.self, from: data!)
并崩溃:
fatal error: 'try!' expression unexpectedly raised an error:
Swift.DecodingError.dataCorrupted(
Swift.DecodingError.Context(
codingPath: [
Test_App.MovieList.CodingKeys.movies,
Foundation.(_JSONKey in _12768CA107A31EF2DCE034FD75B541C9)(stringValue: "Index 0", intValue: Optional(0)),
Test_App.Movie.CodingKeys.dateUpdated
],
debugDescription: "Date string does not match format expected by formatter.",
underlyingError: nil)
)
您可以为此使用 DateDecodingStrategy.custom
选项。一个简短的例子:
let shortFormatter = DateFormatter()
let longFormatter = DateFormatter()
shortFormatter.dateFormat = "yyyy-MM-dd"
longFormatter.dateFormat = "yyyy-MM-dd hh:mm:ss"
func customDateFormatter(_ decoder: Decoder) throws -> Date {
let dateString = try decoder.singleValueContainer().decode(String.self)
let dateKey = decoder.codingPath.last as! Movie.CodingKeys
switch dateKey {
case .shortDate :
return shortFormatter.date(from: dateString)!
case .longDate :
return longFormatter.date(from: dateString)!
default:
fatalError("Unexpected date coding key: \(dateKey)")
}
}
我在 DateFormatter
函数之外 创建了两个实例 只是为了优化。因此,每次调用都不需要 recreate/configure 每个解码日期。
最后,使用我们在上面创建的函数设置 dateDecodingStrategy
:
let json =
"""
{
"name": "A Clockwork Orange",
"short_date": "2017-10-10",
"long_date": "2017-10-10 12:21:02"
}
""".data(using: .utf8)!
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .custom(customDateFormatter)
let movie = try! decoder.decode(Movie.self, from: json)