{
"responseBody": {
"table": {
"data": [
[
"Forth Record",
null,
0,
"2018-08-23T18:30:01.000+0000",
0,
0,
"HCL",
"b74d10ef4fe246948cd036071787ff25"
],
[
"Third Record",
"Testing custom object record 3",
348,
"2018-08-22T18:30:01.000+0000",
36.45,
4545.45,
"HCL",
"139fdba94bb143849fef220f105d66d0"
],
[
"Second Record",
"Testing custom object record 2",
56,
"2018-08-22T18:30:01.000+0000",
6577.67,
567.67,
"HAL",
"606a06c93ea2473fb832e5daafa02df9"
],
[
"First Record",
"Testing custom object record",
75,
"2018-08-22T18:30:01.000+0000",
47.54,
67.63,
"HBL",
"29c4125f3fa947b9b252318305e986c7"
]
]
}
}
}
I want to parse above JSON
using swift 4 Codable
. Please see my objects hierarchy below
//ViewRecordResponse.swift
import Foundation
struct ViewRecordResponse : Codable {
let responseBody : ViewRecord?
enum CodingKeys: String, CodingKey {
case responseBody = "responseBody"
}
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
responseBody = try values.decodeIfPresent(ViewRecord.self, forKey: .responseBody)
}
}
//ViewRecord.swift
import Foundation
struct ViewRecord : Codable {
let table : Table?
enum CodingKeys: String, CodingKey {
case table = "table"
}
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
table = try values.decodeIfPresent(Table.self, forKey: .table)
}
}
//Table.swift
import Foundation
struct Table : Codable {
let data : [[String?]]?
enum CodingKeys: String, CodingKey {
case data = "data"
}
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
data = try values.decodeIfPresent([[String?]].self, forKey: .data)
}
}
but when I try to decode the JSON using Codeable Mapping I got an error saying
The data couldn't be read because it is missing.
The data couldn’t be read because it isn’t in the correct format.
code for decode to JSON object
do {
let jsonDecoder = JSONDecoder()
let response = try jsonDecoder.decode(ViewRecordResponse.self, from: data)
} catch let error {
print(error.localizedDescription)
}
Printing description of data:
▿ 557 bytes
- count : 557
▿ pointer : 0x0000000104a23005
- pointerValue : 4372705285
"data": [
[
456,
31.04,
10000,
"Dummy Data",
"text area dummy",
"2018-08-27T18:30:01.000+0000",
"UE",
"4e67d5c02b0147b1bcfc00f459c0c612"
],
Codable allows you to insert an additional clarifying stage into the process of decoding data into a Swift object. This stage is the “parsed object,” whose properties and keys match up directly to the data, but whose types have been decoded into Swift objects.
The Codable protocol in Swift is really a union of two protocols: Encodable and Decodable . These two protocols are used to indicate whether a certain struct, enum, or class, can be encoded into JSON data, or materialized from JSON data.
Codable is a type that can convert itself into and out of an external representation, where the representation is JSON or a similar format. The Swift standard library contains types like String , Int , Double , Date , Data , and URL that already conform to Codable .
The main issue is that the nested array in data
is not [[String?]]
, there are also Int
and Double
values. That's most likely the cause of the error.
My suggestion is to use the (rather underestimated) unkeyedContainer
to decode the inner array into a struct. decodeIfPresent
handles the null
value.
Your structs can be simplyfied, the coding keys and initializers can be omitted
struct ViewRecordResponse : Codable {
let responseBody : ViewRecord
}
struct ViewRecord : Codable {
let table : Table
}
struct Table : Codable {
let data : [Record]
}
struct Record : Codable {
let name : String
let description : String?
let index : Int
let date : String
let double1 : Double
let double2 : Double
let abbrev : String
let sha : String
init(from decoder: Decoder) throws {
var arrayContrainer = try decoder.unkeyedContainer()
name = try arrayContrainer.decode(String.self)
description = try arrayContrainer.decodeIfPresent(String.self)
index = try arrayContrainer.decode(Int.self)
date = try arrayContrainer.decode(String.self)
double1 = try arrayContrainer.decode(Double.self)
double2 = try arrayContrainer.decode(Double.self)
abbrev = try arrayContrainer.decode(String.self)
sha = try arrayContrainer.decode(String.self)
}
}
I discourage from putting each struct in a separate file as they belong together.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With