问题描述
当尝试从API解析返回数据时,系统显示“数据格式不正确,因此无法读取”。因为返回不一致。
当logo_url具有值时,它是一个对象,请参见下面的示例:
"logo_url": {
"mime_type": "image/jpeg","url": "http://google.com"
},
但是当它确实有值时,它会返回空数组
"logo_url": [],
这就是为什么我收到“由于格式不正确而无法读取数据”的原因。
我的模特
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
}
}
解决方法
如果您无法更改这个写得不好的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
}
}
}
,
我个人更喜欢先检查logo_url
是否为数组,然后在尝试解码密钥时使用try
而不是try?
让Swift报告错误(如果发生任何情况)。由于在大多数情况下,您可能想知道为什么解码失败,而不是仅仅得到nil
。
另外,您可能希望将.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)