How to encode nested arrays with JSONEncoder

665 Views Asked by At

I am trying to encode four different arrays into a json format with JSONEncoder, but I am unable to convert the arrays. So, please help me out. I am using swift 4, xcode 9 for iOS 11.

My arrays are:

var timeCart //dynamic data as string
var nameCart //dynamic data as string, ex. ["myNameOne", "myNameTwo", ...]
var quantityCart //dynamic data as Int, ex. [2, 3, 5, ...]
var priceCart //dynamic data as Int, ex. [82, 73, 65, ...]

my structs are:

struct OrderDetailJSON: Encodable {
    let allOrder: [AllOrder]
    let TaxDetials: TaxDetail

    struct AllOrder: Encodable {
        let date_time: String
        let item: String
        let name: String
        let price: String
    }

    struct TaxDetail: Encodable {
        let tax_per: String
        let tax_name: String
    }
}

I am trying to encode it like this, inside a table view

let orderDetailsJSON = OrderDetailJSON(allOrder: [.init(date_time: "\(quantityCart[indexPath.row])", item: "\(quantityCart[indexPath.row])", name: "\(nameCart[indexPath.row])", price: "\(priceCart[indexPath.row])")], TaxDetials: .init(tax_per: defaults.string(forKey: "STORE_TAX")!, tax_name: defaults.string(forKey: "STORE_TAX_NAME")!))
        do {
            let jsonData = try JSONEncoder().encode(orderDetailsJSON)
            let jsonString = String(data: jsonData, encoding: .utf8)
            print("order_details :" + jsonString!)
        }catch{

        }

the output I am getting is:

order_details: {
  "TaxDetials": {
    "tax_per": "5",
    "tax_name": "CGST & SGST"
  },
  "allOrder": [
    {
      "date_time": "2",
      "name": "Manchurian",
      "item": "2",
      "price": "87"
    }
  ]
}order_details: {
  "TaxDetials": {
    "tax_per": "5",
    "tax_name": "CGST & SGST"
  },
  "allOrder": [
    {
      "date_time": "3",
      "name": "Paneer Tikka",
      "item": "3",
      "price": "150"
    }
  ]
}order_details: {
  "TaxDetials": {
    "tax_per": "5",
    "tax_name": "CGST & SGST"
  },
  "allOrder": [
    {
      "date_time": "2",
      "name": "snacks",
      "item": "2",
      "price": "54"
    }
  ]
}

and the output I am expecting is:

order_details: {
  "TaxDetials": {
    "tax_per": "5",
    "tax_name": "CGST & SGST"
  },
  "allOrder": [
    {
      "date_time": "2",
      "name": "Manchurian",
      "item": "2",
      "price": "87"
    },
    {
      "date_time": "3",
      "name": "Paneer Tikka",
      "item": "3",
      "price": "150"
    },
    {
      "date_time": "2",
      "name": "snacks",
      "item": "2",
      "price": "54"
    }
  ]
}
1

There are 1 best solutions below

4
On

There's nothing wrong with your struct declarations (other than the fact that you should conform to the Swift naming convention, which is lowerCamelCase for variable names - taxPer instead of tax_per, etc. and that your property names don't use the correct plural/singular forms).

The issue is that you are defining an OrderDetailJSON instance for each table view cell, while it seems that your TaxDetails should be the same for all cells in the table and you actually want to create a single OrderDetailJSON instance whose allOrder array property contains one AllOrder instance for each table view cell. You'll need to change the allOrder property to mutable for this to work.

class YourTableViewController: UITableViewController {
    var orderDetails: OrderDetailJSON
    ...
    // You might need to use a different tableView function depending on your exact needs
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        orderDetails.allOrder[indexPath.row] = AllOrder(date_time: "\(quantityCart[indexPath.row])", item: "\(quantityCart[indexPath.row])", name: "\(nameCart[indexPath.row])", price: "\(priceCart[indexPath.row])")
    }
}

You need to make sure that orderDetails is initialized with the correct TaxDetails and that you preallocate the same number of elements to allOrder as many table view cells you'll have. You only need to convert the orderDetails to JSON once all cells have been filled up with information, you don't need to do it on a cell by cell basis.