简体   繁体   中英

How to decode a JSON with 2 structs that has an array

I'm trying to decode a JSON response but I get an error that says:

The data couldn't be read because it isn't in the correct format

The response is in array that went in a ["Product"] node. I get responses but I think the node in ["PictureCollection"] is not properly decoded due to my incorrect format.

Here is the API response. Some API objects are not yet needed. Only the properties I included in Product.swift model.

"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”

This is my code:

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)

    }

The issue is with the struct PictureCollection .

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

In the JSON you provided, URL is an array of String . But in the model PictureCollection , you are using URL of type String .

So, your struct PictureCollection should be,

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

And, there is no need to use force-unwrapped types ( ! ) here. Avoid using them unnecessarily. It might result in runtime exception.

Also, embed your call to decode(_:from:) in a do-catch block and print the whole error object in the catch block to find the exact reason for the issue, ie

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

I here below add code please use this:

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: - Product

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: - PictureCollection

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
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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