如何使用具有数组的 2 个结构解码 JSON

Posted

技术标签:

【中文标题】如何使用具有数组的 2 个结构解码 JSON【英文标题】:How to decode a JSON with 2 structs that has an array 【发布时间】:2019-08-09 06:25:32 【问题描述】:

我正在尝试解码 JSON 响应,但收到一条错误消息:

由于格式不正确,无法读取数据

响应位于["Product"] 节点中的数组中。我收到了回复,但我认为 ["PictureCollection"] 中的节点由于格式不正确而未正确解码。

这是 API 响应。一些 API 对象还不需要。只有我包含在 Product.swift 模型中的属性。

"RMessage" : "OK",
"RSuccess" : true,
"RValue" : null,
"InputKeyword" : “Soap”,
"ProductSearchMode" : 4,
"Product" : [

  "MinPrice" : 2000,
  "Gname" : “Soap Brand 1”,
  "MaxPrice" : 3190,
  "IconFlgList" : [

  ],
  "SoldoutFlg" : null,
  "PictureCollection" : 
    "Count" : 1,
    "URL" : [
      "https:someURL.jpg"
    ]
  ,
  "ProgramBroadcastDate" : null,
  "ID" : 107,
  "Icon2OffValue" : “555”,
  "Gcode" : “3333”
,

  "Gcode" : “3334”,
  "IconFlgList" : [

  ],
  "PictureCollection" : 
    "Count" : 1,
    "URL" : [
      "https:https:someURL1.jpg"
    ]
  ,
  "MaxPrice" : 2100,
  "SoldoutFlg" : null,
  "Icon2OffValue" : “551”,
  "ProgramBroadcastDate" : null,
  "ID" : 108,
  "MinPrice" : 2001,
  "Gname" : "Soap Brand 2”

这是我的代码:

struct Product: Codable 

var id : Int!
var gcode : String!
var gname : String!
var minPrice : Int!
var maxPrice : Int!
var pictureCollection : PictureCollection

enum CodingKeys : String, CodingKey 
    case id = "ID"
    case gcode = "GCode"
    case gname = "Gname"
    case minPrice = "MinPrice"
    case maxPrice = "MaxPrice"
    case pictureCollection = "PictureCollection"



struct PictureCollection : Codable 
var Count : Int!
var URL : String!


var product : Product!
var productArray = [Product]()


let jsonResult = JSON(data)

for json in jsonResult["Product"].arrayValue 
        let jsonData = try json.rawData()
        self.product = try JSONDecoder().decode(Product.self,   from: jsonData)
        self.productArray.append(self.product)

    

【问题讨论】:

你的问题很混乱。请花更多时间准备您的问题。没有名为 picture 的元素。不清楚您要解码什么。 你不应该try 这样的方法。抓住DecodingError。它会准确地告诉你哪里出了问题。 @Desdenova 对不起,我把你弄糊涂了。底部有一个 catch 块,错误为“无法读取数据,因为它的格式不正确” 确保像print(error)这样打印错误对象以获取完整的错误消息 发布一个有效的json,我会尽力帮助你。 【参考方案1】:

问题在于struct PictureCollection

struct PictureCollection : Codable 
   var count : Int!
   var url : String!

在您提供的 JSON 中,URLarrayString。但在模型PictureCollection 中,您使用的是URL 类型的String

所以,你的struct PictureCollection 应该是,

struct PictureCollection : Codable 
   var count : Int
   var url : [String]

而且,这里没有必要使用强制解包类型 (!)。避免不必要地使用它们。可能会导致运行时异常。

另外,将您对decode(_:from:) 的调用嵌入到do-catch 块中,并在catch 块中打印整个error 对象,以找出问题的确切原因,即

do
    //decode the JSON here...
 catch 
    print(error)

【讨论】:

你好。你的回答对我来说是正确的,但我认为你的意思是这样吗? struct PictureCollection : Codable var Count : Int!变量网址:[字符串] @dreiohc 对。那只是复制粘贴错误。 我想到了这个,但没有尝试。我认为这太简单了。我会记下力展开的。感谢您的帮助。 您无法读取这样的JSONDecoder 错误。您需要抓住 DecodingError 并阅读其上下文的 debugDescriptioncodingPath 以了解实际错误。 @Desdenova 尝试打印错误,它将提供问题所在的所有详细信息。【参考方案2】:

我在下面添加代码请使用这个:

class Welcome: Codable 
        let rMessage: String
        let rSuccess: Bool
        let rValue:Int?
        let inputKeyword: String
        let productSearchMode: Int
        let product: [Product]

        enum CodingKeys: String, CodingKey 
            case rMessage = "RMessage"
            case rSuccess = "RSuccess"
            case rValue = "RValue"
            case inputKeyword = "InputKeyword"
            case productSearchMode = "ProductSearchMode"
            case product = "Product"
        

        init(rMessage: String, rSuccess: Bool, rValue: JSONNull?, inputKeyword: String, productSearchMode: Int, product: [Product]) 
            self.rMessage = rMessage
            self.rSuccess = rSuccess
            self.rValue = rValue
            self.inputKeyword = inputKeyword
            self.productSearchMode = productSearchMode
            self.product = product
        
    

// MARK: - 产品

class Product: Codable 
    let minPrice: Int
    let gname: String
    let maxPrice: Int
    let iconFlgList: [String]
    let soldoutFlg:bool?
    let pictureCollection: PictureCollection
    let programBroadcastDate:String?
    let id: Int
    let icon2OffValue, gcode: String

    enum CodingKeys: String, CodingKey 
        case minPrice = "MinPrice"
        case gname = "Gname"
        case maxPrice = "MaxPrice"
        case iconFlgList = "IconFlgList"
        case soldoutFlg = "SoldoutFlg"
        case pictureCollection = "PictureCollection"
        case programBroadcastDate = "ProgramBroadcastDate"
        case id = "ID"
        case icon2OffValue = "Icon2OffValue"
        case gcode = "Gcode"
    

    init(minPrice: Int, gname: String, maxPrice: Int, iconFlgList: [JSONAny], soldoutFlg: JSONNull?, pictureCollection: PictureCollection, programBroadcastDate: JSONNull?, id: Int, icon2OffValue: String, gcode: String) 
        self.minPrice = minPrice
        self.gname = gname
        self.maxPrice = maxPrice
        self.iconFlgList = iconFlgList
        self.soldoutFlg = soldoutFlg
        self.pictureCollection = pictureCollection
        self.programBroadcastDate = programBroadcastDate
        self.id = id
        self.icon2OffValue = icon2OffValue
        self.gcode = gcode
    

// MARK: - 图片集

class PictureCollection: Codable 
    let count: Int
    let url: [String]

    enum CodingKeys: String, CodingKey 
        case count = "Count"
        case url = "URL"
    

    init(count: Int, url: [String]) 
        self.count = count
        self.url = url
    

【讨论】:

不要将引用类型用作可编码的,除非它是您稍后需要改变的表单对象。这也不能以任何方式回答问题。 为什么要在结构体中添加 OP 不感兴趣的字段? 根据类名猜测 Welcome,我猜 nimesh 使用 app.quicktype.io 生成代码

以上是关于如何使用具有数组的 2 个结构解码 JSON的主要内容,如果未能解决你的问题,请参考以下文章

如何使用数组对 API 数据进行 Json 解码?

JSON 可解码嵌套数组具有不同的格式和类型

在 Swift 中解码 JSON API - 重复的结构名称

如何在 Swift 中解码具有许多唯一键的嵌套 JSON?

如何解组具有不同类型值的json数组

当属性类型可能从 Int 更改为 String 时,如何使用 Decodable 协议解析 JSON?