我试图使用Swift Decoder协议来解析一些JSON,但是我得到了一些我无法理解的错误。我得到的JSON是有问题的,因为并不是所有的键都一定存在,所以我给相应结构的属性设置了默认值,并设置了一个初始化器,但我怀疑我的方法是错误的。
在 "food "数组中,有些项的属性是 "ndbNumber"(String),有些项的属性是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: "food", intValue: nil), _JSONKey(stringValue: "Index 4", intValue: 4), CodingKeys(stringValue: "ndbNumber", intValue: nil)], debugDescription: "预期解码Int,但发现了一个stringdata。", underlyingError: 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.govfdcv1foodssearch?query=cheddar&dataType=Foundation,Branded&api_key=DEMO_KEY。
我希望能得到任何解决这个问题的帮助。
你的键有类型不匹配的问题。foods
和 ndbNumber
,用这个结构来解码。
struct ReturnedFoods: Codable {
let foodSearchCriteria: FoodSearchCriteria
let totalHits, currentPage, totalPages: Int
let foods: [Food]
}
struct FoodSearchCriteria: Codable {
let dataType: [String]
let query, generalSearchInput: String
let pageNumber: Int
let requireAllWords: Bool
}
struct Food: Codable {
let fdcID: Int
let description, dataType, gtinUpc, publishedDate: String
let brandOwner, ingredients: String
let foodNutrients: [FoodNutrient]
let allHighlightFields: String
let score: Double
enum CodingKeys: String, CodingKey {
case fdcID = "fdcId"
case description, dataType, gtinUpc, publishedDate, brandOwner, ingredients, foodNutrients, allHighlightFields, score
}
}
struct FoodNutrient: Codable {
let nutrientID: Int
let nutrientName, nutrientNumber, unitName: String
let derivationCode: DerivationCode
let derivationDescription: String
let value: Double
enum CodingKeys: String, CodingKey {
case nutrientID = "nutrientId"
case nutrientName, nutrientNumber, unitName, derivationCode, derivationDescription, value
}
}
enum DerivationCode: String, Codable {
case lccd = "LCCD"
case lccs = "LCCS"
}