简体   繁体   English

如何在来自 API 的未指定返回数据中使用可解码

[英]How can I use decodable in unspecified return data from API

when trying to parse return data from API im getting "The data couldn't be read because it isn't in the correct format."当试图解析来自 API 的返回数据时,我得到“无法读取数据,因为它的格式不正确。” because the return is inconsistent.因为回报不一致。

When logo_url has value it was a object see example below:当 logo_url 具有值时,它是 object,请参见下面的示例:

"logo_url": {
                    "mime_type": "image/jpeg",
                    "url": "http://google.com"
                },

But when it doenst have value its return empty array但是当它没有值时,它返回空数组

"logo_url": [],

This is the reason why im getting "The data couldn't be read because it isn't in the correct format."这就是为什么我得到“无法读取数据,因为它的格式不正确”的原因。

My model我的 model

struct Model: Decodable {
    let logo: Logo?

    enum CodingKeys: String, CodingKey {
        case logo = "logo_url"
    }
}

struct Logo: Decodable {
    
    let mimeType: String?
    let url: String?
    
    enum CodingKeys: String, CodingKey {
        case mimeType = "mime_type"
        case url
    }
}

If you can't change this badly written API, you'd need a custom decoder, where you basically attempt to decode as the type you want, and failing that - make it nil :如果你不能改变这个写得很糟糕的 API,你需要一个自定义解码器,你基本上会尝试解码为你想要的类型,如果失败了 - 让它nil

struct Model: Decodable {
    let logo: Logo?

    enum CodingKeys: String, CodingKey {
        case logo = "logo_url"
    }
    
    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        
        if let logo = try? container.decode(Logo.self, forKey: .logo) {
            self.logo = logo
        } else {
            self.logo = nil
        }
    }
}

I personally prefer checking if the logo_url is an array first, then let Swift report error if there is any happens by using try instead of try?我个人更喜欢先检查logo_url是否是一个数组,然后让 Swift 报告错误,如果使用try而不是try? when trying to decode a key.尝试解码密钥时。 Since in most cases, you may want to know why your decoding failed instead of just getting nil as a result.因为在大多数情况下,您可能想知道解码失败的原因,而不是仅仅得到nil

Additionally, you may want to use .convertFromSnakeCase as a keyDecodingStrategy so you don't have to write extra code.此外,您可能希望使用.convertFromSnakeCase作为keyDecodingStrategy ,这样您就不必编写额外的代码。

let json2 = """
{
  "logo_url": {
    "mime_type": "image/jpeg",
    "url": "http://google.com"
  }
}
"""

let json3 = "[]"

struct Logo: Decodable {
  let mimeType: String
  let url: String
}

struct Model: Decodable {
  let logo: Logo?

  private enum CodingKeys: String, CodingKey {
      case logoUrl
  }

  init(from decoder: Decoder) throws {
    let container = try decoder.container(keyedBy: CodingKeys.self)
    if (try? container.decode([String].self, forKey: .logoUrl)) != nil {
      self.logo = nil
    } else {
      self.logo = try container.decode(Logo.self, forKey: .logoUrl)
    }
  }
}

let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase

let result2 = try decoder.decode(Model.self, from: json2.data(using: .utf8)!)
print(result2)

let result3 = try? decoder.decode(Model.self, from: json3.data(using: .utf8)!)
print(result3)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM