Decoding a Nested Array in Swift 4

decoding a nested array in swift 4

If you want to take advantage of JSONDecoder you have to create a nested struct(ure).

I recommend to use the name Root for the root object and put the child struct into Root

struct Root : Decodable {

struct User : Decodable {
let id: Int
let name: String
}

let users : [User]
}

let json = """
{
"users": [{"id": 1, "name":"John Doe"},
{"id": 2, "name":"Luke Smith"}]
}
"""

let data = Data(json.utf8)
do {
let root = try JSONDecoder().decode(Root.self, from: data)
print(root.users)
} catch {
print(error)
}

No Data when Decoding Nested Array in Json by Swift

This code is enough:

struct PriceList: Decodable {
let success: Bool
let message: String
let response: [ResponseList]

enum CodingKeys: String, CodingKey {
case success = "IsSuccess"
case message = "Message"
case response = "ResponseData"
}
}

struct ResponseList: Decodable {
let packageID: Int
let packageName: String
let price, discountedPrice: Double
let type: String
let testPackageGroupID: Int?
let sampleType: [SampleTypeList]?

enum CodingKeys: String, CodingKey {
case packageID = "PackageId"
case packageName = "PackageName"
case price = "Price"
case discountedPrice = "DiscountedPrice"
case type = "Type"
case testPackageGroupID = "TestPackageGroupId"
case sampleType = "SampleTypeList"
}
}

struct SampleTypeList: Decodable {
let testSampleTypeID: String
let sampleName: String
let colourCode: String
enum CodingKeys: String, CodingKey {
case testSampleTypeID = "TestSampleTypeId"
case sampleName = "SampleName"
case colourCode = "ColourCode"
}
}

What I did fix, what I didn't like from your sample code:

  • Please name your variables starting with a lowercase, it's convention, and is easier to read (if everyone follow the same convention/standards).
  • Make your code compilable for us. It's not that hard, but if anyone would want to help you, it be much easier for us to just copy/paste your code and test it and not fix everything in it. You'll have better chances to get an answer. There is a Cannot assign value of type 'String' to type 'Int' because packageID is set as an Int and trying to be decoded as a String, there are missing spaces: variable= instead of variable =, etc. It's annoying to have us to fix that to be able to work.
  • You printed the JSON, that's a good point, to test it, there is no need anymore of the Web API Call, see following sample
  • You said that some values can be null, so please provide a JSON with these sample, cut if needed, see the JSON I used as sample, I checked on a JSON online validator that is was valid, and that's all. Since you that that 2 values could be null, I used all possibilities: one with none null, one with one null, one with the other null, and one with both null. Then, for each of these, I put the values as optional.
  • I removed all the init(from decoder:) as they are useless. If you decode each value with let container = try decoder.container(keyedBy:CodingKeys.self); variable = try container.decode(VariableType.self,forKey: .correspondingCodingKeyInTheEnumCase), that code is already done internally by Apple when compiling.

With sample test:

let jsonStr = """
{
"IsSuccess": true,
"Message": "Data Returned",
"ResponseData": [{
"PackageId": 1025,
"PackageName": "17 OH Progesterone",
"Price": 0.00,
"DiscountedPrice": 1.0,
"Type": "Test",
"TestPackageGroupId": 3,
"SampleTypeList": [{
"TestSampleTypeId": "50",
"SampleName": "Serum",
"ColourCode": "#FFB500"
}]
},
{
"PackageId": 1916,
"PackageName": "24 hour Albumin creatinine ratio (ACR)",
"Price": 120.00,
"DiscountedPrice": 1.0,
"Type": "Test",
"TestPackageGroupId": 3,
"SampleTypeList": null
},
{
"PackageId": 1914,
"PackageName": "24 Hour Microalbumin Creatinine Ratio",
"Price": 110.00,
"DiscountedPrice": 1.0,
"Type": "Test",
"TestPackageGroupId": null,
"SampleTypeList": [{
"TestSampleTypeId": "66",
"SampleName": "24 hrs Urine",
"ColourCode": "#212DC1"
}]
},
{
"PackageId": 1913,
"PackageName": "24 Hours Protein Creatinine Ratio (PCR) ",
"Price": 12.00,
"DiscountedPrice": 1.0,
"Type": "Test",
"TestPackageGroupId": null,
"SampleTypeList": null
}
]
}
"""

do {
let priceList = try JSONDecoder().decode(PriceList.self, from: Data(jsonStr.utf8))
print(priceList)
} catch {
print("Error while decoding: \(error)")
}

How to decode a dictionary with a nested array inside?

Change the type of searchResults from [String: AnyObject] to 'SearchResults'

var searchResults : SearchResults?

JSON decoding double nested array in Swift

Where do you decode the days key? That's the problem. You need an intermediate struct

struct Root : Decodable {
let itenaries : Itenary
}

struct Itenary : Decodable {
let days : [[Days]]
}

...

let result = try decoder.decode(Root.self, from: fileData)
print(result.iternaries.days[0][0].itenary_id)

Swift 4 Decodable: struct from nested array

You can use nestedContainer(keyedBy:) and nestedUnkeyedContainer(forKey:) for decoding nested array and dictionary like this to turn it into your desired structure. Your decoding in init(decoder: ) might look something like this,

Actor extension for decoding,

extension Actor: Decodable {

enum CodingKeys: CodingKey { case id, name }

enum ActorKey: CodingKey { case actor }

init(from decoder: Decoder) throws {
let rootKeys = try decoder.container(keyedBy: ActorKey.self)
let actorContainer = try rootKeys.nestedContainer(keyedBy: CodingKeys.self,
forKey: .actor)
try id = actorContainer.decode(Int.self,
forKey: .id)
try name = actorContainer.decode(String.self,
forKey: .name)
}
}

PlaceholderData extension for decoding,

extension PlaceholderData: Decodable {

enum CodingKeys: CodingKey { case filmCount, year, category, actors }

enum NodeKeys: CodingKey { case nodes }

init(from decoder: Decoder) throws {
let rootContainer = try decoder.container(keyedBy: CodingKeys.self)
try filmCount = rootContainer.decode(Int.self,
forKey: .filmCount)
try year = rootContainer.decode(Int.self,
forKey: .year)
try category = rootContainer.decode(String.self,
forKey: .category)
let actorsNode = try rootContainer.nestedContainer(keyedBy: NodeKeys.self,
forKey: .actors)
var nodes = try actorsNode.nestedUnkeyedContainer(forKey: .nodes)
var allActors: [Actor] = []

while !nodes.isAtEnd {
let actor = try nodes.decode(Actor.self)
allActors += [actor]
}
actors = allActors
}
}

Then, you can decode it like this,

let decoder = JSONDecoder()
do {
let placeholder = try decoder.decode(PlaceholderData.self, from: jsonData)
print(placeholder)
} catch {
print(error)
}

Here, the basic idea is to decode dictionary container using nestedContainer(keyedBy:) and array container using nestedUnkeyedContainer(forKey:)

How to decode nested JSON array and object with JSONDecoder in swift 4.1 and xcode 9.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"}]}


Related Topics



Leave a reply



Submit