2

I am new to iOS and I am having trouble decoding a nested JSON file which has many nested arrays and objects. I am using JSONDecoder to decode, but somewhere I am making a mistake or not decoding correctly.

my decoder is

let myOrder = try JSONDecoder().decode(MyOrder.self, from: data!)
                    for items in myOrder.OrderDetials {
                        self.orders.append(MyOrders(order_id: items.order_id!, order_ref_number: items.order_ref_number!, cust_mob: items.cust_mob!, store_name: items.store_name!, store_id: items.store_id!, order_details: items.order_details!, order_amount: items.order_amount!, order_status: items.order_status!, order_status_remark: items.order_status_remark!, order_place_at: items.order_place_at!, order_status_change_at: items.order_status_change_at!))
                        print(items.cust_mob!)
                    }
                    print(myOrder)

The error its throwing is

typeMismatch(Swift.Array<Any>, Swift.DecodingError.Context(codingPath: [CodingKeys(stringValue: "OrderDetials", intValue: nil), _JSONKey(stringValue: "Index 0", intValue: 0), CodingKeys(stringValue: "order_details", intValue: nil)], debugDescription: "Expected to decode Array<Any> but found a string/data instead.", underlyingError: nil))

my structures are

struct MyOrder: Decodable {
    var OrderDetials: [OrderDetails]
}

struct OrderDetails: Decodable {
    var order_id: String?
    var order_ref_number: String?
    var cust_mob: String?
    var store_name: String?
    var store_id: String?
    var order_details: OrderItems?
    var order_amount: String?
    var order_status: String?
    var order_status_remark: String?
    var order_place_at: String?
    var order_status_change_at: String?

}

struct OrderItems: Decodable {
    var allorder: [AllOrder]
    var TaxDetials: [TaxDetails]


    struct AllOrder: Decodable {
        var date_time: String?
        var item: String?
        var name: String?
    }
    struct TaxDetails: Decodable {
        var tax_per: String?
        var tax_name: String?
    }

}

and DataModel class

class MyOrders {
    var order_id: String
    var order_ref_number: String
    var cust_mob: String
    var store_name: String
    var store_id: String
    var order_details: OrderItems?
    var order_amount: String
    var order_status: String
    var order_status_remark: String
    var order_place_at: String
    var order_status_change_at: String?

    init(order_id: String, order_ref_number: String, cust_mob: String, store_name: String, store_id: String, order_details: OrderItems?, order_amount: String, order_status: String, order_status_remark: String, order_place_at: String, order_status_change_at: String?) {
        self.order_id = order_id
        self.order_ref_number = order_ref_number
        self.cust_mob = cust_mob
        self.store_name = store_name
        self.store_id = store_id
        self.order_details = order_details
        self.order_amount = order_amount
        self.order_status = order_status
        self.order_status_remark = order_status_remark
        self.order_place_at = order_place_at
        self.order_status_change_at = order_status_change_at
    }
}

class MyItems {
    var item: String
    var name: String
    var price: String

    init(item: String, name: String, price: String) {
        self.item = item
        self.name = name
        self.price = price
    }
}

my JSON is

{
    "OrderDetials": [
        {
            "order_id": "11",
            "order_ref_number": "MM1525235813",
            "cust_mob": "9958324531",
            "store_name": "Moti mahal",
            "store_id": "1",
            "order_details": "{'allorder':[{\"date_time\":\"\",\"item\":\"2\",\"name\":\"CHICKN ROLL\",\"price\":\"360\"}]}{\"TaxDetials\":[{\"tax_per\":\"5\",\"tax_name\":\"CGST & SGST\"}]}",
            "order_amount": "378.0",
            "order_status": "1",
            "order_status_remark": "New_Order_Place",
            "order_place_at": "2018-05-02 10:06:53",
            "order_status_change_at": null
        }
    ]
}

please someone tell me how to decode it correctly or what changes I need to do in structures.

5
  • 1
    Your value for "order_details" key is string and your struct is treating it as Array.You have to change value of "order_details" key according to your defined struct to make it work Commented May 17, 2018 at 5:33
  • your order_details contains the structure like JSON not string Commented May 17, 2018 at 5:39
  • I tried doing this: "var order_details: String?" and this: "var order_details: [OrderItems]?" both are giving same errors. @Vikky Commented May 17, 2018 at 5:45
  • var order_details: String? is working Commented May 17, 2018 at 6:00
  • Checkout this article, it explains really well medium.com/@nimjea/json-parsing-in-swift-2498099b78f Commented Sep 24, 2018 at 10:00

1 Answer 1

3

OrderDetials is Array of Dictionary [[String: String?]] , and your Initial response is Dictionary also order_details is Wrong json String not Dictionary , so we will parse it as string , in Codable every dictionary {} is converted t Struct or Class and [] is Array

Model:

import Foundation

struct Initial: Codable {
    let orderDetials: [OrderDetial]

    enum CodingKeys: String, CodingKey {
        case orderDetials = "OrderDetials"
    }
}

struct OrderDetial: Codable {
    let orderID, orderRefNumber, custMob, storeName: String
    let storeID, orderDetails, orderAmount, orderStatus: String
    let orderStatusRemark, orderPlaceAt: String
    let orderStatusShangeAt:String?

    enum CodingKeys: String, CodingKey {
        case orderID = "order_id"
        case orderRefNumber = "order_ref_number"
        case custMob = "cust_mob"
        case storeName = "store_name"
        case storeID = "store_id"
        case orderDetails = "order_details"
        case orderAmount = "order_amount"
        case orderStatus = "order_status"
        case orderStatusRemark = "order_status_remark"
        case orderPlaceAt = "order_place_at"
        case orderStatusShangeAt = "order_status_change_at"


    }
}


// MARK: Convenience initializers

extension Initial {
    init(data: Data) throws {
        self = try JSONDecoder().decode(Initial.self, from: data)
    }
}

Used Like this :

   if  let initial =  try? Initial.init(data: data){

                for item in initial.orderDetials {
                    print(item.orderAmount)
                    print(item.orderDetails) // here is Wrong format from your Server API
                }
           }

Order_details is wrong

{'allorder':[{"date_time":"","item":"2","name":"CHICKN ROLL","price":"360"}]}{"TaxDetials":[{"tax_per":"5","tax_name":"CGST & SGST"}]}
Sign up to request clarification or add additional context in comments.

5 Comments

Now I got orderDetails as String. Do I need to use JSONSerialization to access data inside it or JSONDecoder will automatically do that?
yes you cnan parse it again but it also wrong check this 'allorder' not "allorder"
Thanks, actually the JSON is generated by API team and also android team is using the same JSON and it's working there, So I have to use the same JSON.
No, it's same as on server. I have double checked.
ok so your backend developer is wrong you can check with your android developer may be he format this string with any other way , but this wrong Json and wrong json string

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.