2017-10-19 2 views
1

JSONDecoder.DateDecodingStrategyJSONDecoder에 여러 개 추가 할 수 있습니까? 이제여러 개의 날짜를 디코딩 할 수있는 디코딩 가능 코드

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와 같은 형식의 데이터를 보냅니다.

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의 예를 게시 할 수 마지막으로

, 우리는 위에서 만든 함수를 사용하여 dateDecodingStrategy을 설정? –

답변

4

당신에게 : 내가 .formatted (myDateFormatter)에 JSONDecoderDateDecodingStrategy을 설정하면

는이 방법

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

디코더에 대한 추락 이를 위해 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)") 
    } 
} 

I는 모두 DateFormatter 인스턴스를 생성 외부 기능을 단지 최적화한다. 따라서 각 호출은 각각의 디코딩 된 날짜에 대해 다시 만들거나 구성 할 필요가 없습니다.

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)