【发布时间】:2020-06-03 16:08:15
【问题描述】:
我正在尝试使用 Swift 解码器协议来解析一些 JSON,但是我遇到了一些我无法理解的错误。我返回的 JSON 是有问题的,因为并非所有键都肯定存在,所以我已经给出了相应结构默认值的属性并设置了一个初始化程序,但我怀疑我的方法是错误的。
在“foods”数组中,有些项目具有属性“ndbNumber”(字符串),有些项目具有 fdcId (Int) 和 gtinUpc (String) 属性。否则,这些项目是相同的,并且代表从搜索返回的食品。
这是最外层 JSON 级别的结构。
public struct ReturnedFoods: Decodable {
public let count: Int
public let all: [ReturnedFood]
enum CodingKeys: String, CodingKey {
case count = "totalHits"
case all = "foods"
}
}
这是下一个级别的食物:
public struct ReturnedFood: Codable {
public var ndbNumber: String = ""
public var fdcId : Int = -1
public var description: String = ""
public var dataType : String = ""
public var brandOwner: String = ""
public var gtinUpc : String = ""
public var ingredients : String = ""
public var publishedDate : String = ""
public var score : Float = -1
public init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
if let ndbNumber = try values.decodeIfPresent(String.self, forKey: .ndbNumber) {
self.ndbNumber = ndbNumber
}
if let fdcId = try values.decodeIfPresent(Int.self, forKey: .ndbNumber) {
self.fdcId = fdcId
}
if let description = try values.decodeIfPresent(String.self, forKey: .description) {
self.description = description
}
if let dataType = try values.decodeIfPresent(String.self, forKey: .dataType) {
self.dataType = dataType
}
if let brandOwner = try values.decodeIfPresent(String.self, forKey: .brandOwner) {
self.brandOwner = brandOwner
}
if let gtinUpc = try values.decodeIfPresent(String.self, forKey: .gtinUpc) {
self.gtinUpc = gtinUpc
}
if let ingredients = try values.decodeIfPresent(String.self, forKey: .ingredients) {
self.ingredients = ingredients
}
if let publishedDate = try values.decodeIfPresent(String.self, forKey: .publishedDate) {
self.publishedDate = publishedDate
}
if let score = try values.decodeIfPresent(Float.self, forKey: .score) {
self.score = score
}
}
}
我已经仔细检查以确保所有类型都正确,所以我怀疑问题出在缺少键上。
这是我得到的错误: typeMismatch(Swift.Int, Swift.DecodingError.Context(codingPath: [CodingKeys(stringValue: "foods", intValue: nil), _JSONKey(stringValue: "Index 4", intValue: 4), CodingKeys(stringValue: "ndbNumber", intValue: nil)], debugDescription: "期望解码 Int 但找到了一个字符串/数据。",底层错误: nil))
JSON 很长,所以我只发布一小部分:
"foodSearchCriteria": {
"dataType": [
"Foundation",
"Branded"
],
"query": "cheddar",
"generalSearchInput": "cheddar",
"pageNumber": 1,
"requireAllWords": false
},
"totalHits": 12839,
"currentPage": 1,
"totalPages": 257,
"foods": [
{
"fdcId": 566851,
"description": "CHEDDAR",
"dataType": "Branded",
"gtinUpc": "828280001766",
"publishedDate": "2019-04-01",
"brandOwner": "FISCALINI",
"ingredients": "PASTEURIZED COW'S MILK, CHEESE CULTURES, ENZYMES (MICROBIAL RENNET), SALT.",
"foodNutrients": [
{
"nutrientId": 1079,
"nutrientName": "Fiber, total dietary",
"nutrientNumber": "291",
"unitName": "G",
"derivationCode": "LCCD",
"derivationDescription": "Calculated from a daily value percentage per serving size measure",
"value": 0
},
{
"nutrientId": 1087,
"nutrientName": "Calcium, Ca",
"nutrientNumber": "301",
"unitName": "MG",
"derivationCode": "LCCD",
"derivationDescription": "Calculated from a daily value percentage per serving size measure",
"value": 714
},
{
"nutrientId": 1089,
"nutrientName": "Iron, Fe",
"nutrientNumber": "303",
"unitName": "MG",
"derivationCode": "LCCD",
"derivationDescription": "Calculated from a daily value percentage per serving size measure",
"value": 0
},
{
"nutrientId": 1104,
"nutrientName": "Vitamin A, IU",
"nutrientNumber": "318",
"unitName": "IU",
"derivationCode": "LCCD",
"derivationDescription": "Calculated from a daily value percentage per serving size measure",
"value": 1071
},
{
"nutrientId": 1162,
"nutrientName": "Vitamin C, total ascorbic acid",
"nutrientNumber": "401",
"unitName": "MG",
"derivationCode": "LCCD",
"derivationDescription": "Calculated from a daily value percentage per serving size measure",
"value": 0
},
{
"nutrientId": 1003,
"nutrientName": "Protein",
"nutrientNumber": "203",
"unitName": "G",
"derivationCode": "LCCS",
"derivationDescription": "Calculated from value per serving size measure",
"value": 26.79
},
{
"nutrientId": 1004,
"nutrientName": "Total lipid (fat)",
"nutrientNumber": "204",
"unitName": "G",
"derivationCode": "LCCS",
"derivationDescription": "Calculated from value per serving size measure",
"value": 32.14
},
{
"nutrientId": 1005,
"nutrientName": "Carbohydrate, by difference",
"nutrientNumber": "205",
"unitName": "G",
"derivationCode": "LCCS",
"derivationDescription": "Calculated from value per serving size measure",
"value": 3.57
},
{
"nutrientId": 1008,
"nutrientName": "Energy",
"nutrientNumber": "208",
"unitName": "KCAL",
"derivationCode": "LCCS",
"derivationDescription": "Calculated from value per serving size measure",
"value": 400
},
{
"nutrientId": 1093,
"nutrientName": "Sodium, Na",
"nutrientNumber": "307",
"unitName": "MG",
"derivationCode": "LCCS",
"derivationDescription": "Calculated from value per serving size measure",
"value": 679
},
{
"nutrientId": 1253,
"nutrientName": "Cholesterol",
"nutrientNumber": "601",
"unitName": "MG",
"derivationCode": "LCCS",
"derivationDescription": "Calculated from value per serving size measure",
"value": 111
},
{
"nutrientId": 1257,
"nutrientName": "Fatty acids, total trans",
"nutrientNumber": "605",
"unitName": "G",
"derivationCode": "LCCS",
"derivationDescription": "Calculated from value per serving size measure",
"value": 1.25
},
{
"nutrientId": 1258,
"nutrientName": "Fatty acids, total saturated",
"nutrientNumber": "606",
"unitName": "G",
"derivationCode": "LCCS",
"derivationDescription": "Calculated from value per serving size measure",
"value": 21.43
}
],
"allHighlightFields": "",
"score": 721.74396
这里是完整 JSON 的链接:https://api.nal.usda.gov/fdc/v1/foods/search?query=cheddar&dataType=Foundation,Branded&api_key=DEMO_KEY
对于解决此问题的任何帮助,我将不胜感激。
【问题讨论】:
-
请阅读错误信息。它清楚地表明数组
foods的第5 项中键ndbNumber的值不是Int。但是有一个明显的复制和粘贴错误:您必须为密钥.fdcId而不是.ndbNumber解码fdcId -
你是对的,这是一个愚蠢的复制和粘贴错误。感谢您注意到它。现在可以了。
-
当您的 json 有时缺少参数时,您可以简单地将它们声明为可选项:
public var description: String?
标签: json swift codable decodable