Декодирование json данных в быстром режиме с двумя различными возможными ответами json с сервера на две разные структуры - PullRequest
0 голосов
/ 16 апреля 2020

Когда я делаю запрос API через urlSession на сервер, я могу получить json как

{
    "movie": "Avengers",
    "director": "Joss Whedon",
}

или как этот

{
    "apiKey": "invalid"
}

У меня есть две структуры для сохранения как this

struct Movie: Codable {
    let request: String
    let director: String

    init(movie:String, director:Sring) {
        self.movie = movie
        self.director = director
    }
}

struct Valid: Codable {
    let apiKey: String

    init(apiKey:String) {
        self.apiKey = apiKey
    }
}

На основе ответа я хочу либо декодировать в первую структуру, либо во вторую структуру. Как это сделать.

Ответы [ 3 ]

0 голосов
/ 16 апреля 2020

Прежде всего, типы Codable для разбора вышеуказанных ответов 2 JSON должны выглядеть так:

struct Movie: Decodable {
    let movie: String
    let director: String
}

struct Valid: Decodable {
    let apiKey: String
}

Нет необходимости явно создать init(). Codable будет обрабатывать это автоматически.

Далее вам нужно создать еще один тип Codable, который может обрабатывать оба ответа, т.е.

enum Response: Decodable {
    case movie(Movie)
    case valid(Valid)

    init(from decoder: Decoder) throws {
        let container = try decoder.singleValueContainer()
        do {
            let data = try container.decode(Movie.self)
            self = .movie(data)
        } catch  {
            let data = try container.decode(Valid.self)
            self = .valid(data)
        }
    }
}

Теперь вы можете проанализировать JSON data вот так,

do {
    let response = try JSONDecoder().decode(Response.self, from: data)
    print(response)
} catch {
    print(error)
}
0 голосов
/ 21 апреля 2020

Синтаксический анализ json с одной такой структурой

struct RootClass : Codable {

    let apiKey : String?
    let director : String?
    let movie : String?


    enum CodingKeys: String, CodingKey {
        case apiKey = "apiKey"
        case director = "director"
        case movie = "movie"
    }
    init(from decoder: Decoder) throws {
        let values = try decoder.container(keyedBy: CodingKeys.self)
        apiKey = try values.decodeIfPresent(String.self, forKey: .apiKey)
        director = try values.decodeIfPresent(String.self, forKey: .director)
        movie = try values.decodeIfPresent(String.self, forKey: .movie)
    }


}

И проверьте значение ключа apiKey, если оно равно нулю, затем используйте фильмы и режиссера. или используйте значение apiKey

0 голосов
/ 16 апреля 2020
if let url = URL(string: "myurl.com") {
   URLSession.shared.dataTask(with: url) { data, response, error in
      if let data = data {
        guard let json = data as? [String:AnyObject] else {
              return
        }
          do {
            if let movie =  json["movie"]{
              //moview is there. so you can decode to your movie struct
              let res = try JSONDecoder().decode(Movie.self, from: data)
            }else{
              //move is not there.it means error
              let res = try JSONDecoder().decode(Valid.self, from: data)
            }
          } catch let error {
             print(error)
          }
       }
   }.resume()
}
...