2017-10-19 129 views
1

是否有可能將多個JSONDecoder.DateDecodingStrategy添加到同一個JSONDecoder可解碼的多個DateDecodingStrategy

我得到了一個解碼:

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,2017年10月10日使用了以下模式:opening_date。

但是,對於date_updated,他們發送數據格式如2017-10-10 12:21:02。

當我設置JSONDecoderDateDecodingStrategy到.formatted(myDateFormatter)墜毀名爲這種方式

let decoder = JSONDecoder() 
let dateformatter = DateFormatter() 
dateformatter.dateFormat = "yyyy-MM-dd" 
decoder.dateDecodingStrategy = .formatted(dateformatter) 
let movieList = try! decoder.decode(MovieList.self, from: data!) 

和崩潰的日期date_updated

解碼器:

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) 
) 
+0

你能後的JSON的例子嗎? –

回答

4

你可以使用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實例功能僅僅作爲優化。因此,每次呼叫都不需要爲每個解碼日期重新創建/配置它們。

最後,設置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)