【问题标题】:Decoding json data in swift with two different possible json reponse from server to two different structs使用从服务器到两个不同结构的两种不同的可能 json 响应快速解码 json 数据
【发布时间】:2020-07-29 04:03:45
【问题描述】:

当我通过 urlSession 向服务器发出 api 请求时,我可能会得到类似的 json

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

或者像这样

{
    "apiKey": "invalid"
}

我有两个这样的结构要保存

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
    }
}

根据我想解码为第一个结构或第二个结构的响应。如何做到这一点。

【问题讨论】:

  • 不确定这是否是您希望让开发人员知道他们的 API 密钥是否无效的正确方式。我认为如果你抛出错误会更好,如果它是无效的,如果不是然后发送数据。这样你就不必担心哪个结构被解码了。
  • @JulesL。谢谢。但由于某种原因,我不得不走这条路。我将如何进行解码?
  • 为什么要保存无效响应?如果解码不成功,请忽略“apiKey”。顺便说一句,您的 JSON 字符串和您的结构中没有请求键,它缺少电影属性。

标签: ios json swift codable urlsession


【解决方案1】:
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()
}

【讨论】:

    【解决方案2】:

    使用这样的单个结构解析 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)
        }
    
    
    }
    

    如果它是 nil 则检查 key apiKey 的值,然后使用电影和导演。或者使用apiKey的值

    【讨论】:

      【解决方案3】:

      首先,解析上述 2 个 JSON 响应的 Codable 类型应该如下所示,

      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)
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2023-04-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-07-02
        • 2023-04-04
        • 2015-10-18
        相关资源
        最近更新 更多