I want to decode this data and want to display fields separately in UI. Json data I am receiving from API
{
"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": [
{
"TestSampleTypeId": "66",
"SampleName": "24 hrs Urine",
"ColourCode": "#212DC1"
}
]
},
{
"PackageId": 1914,
"PackageName": "24 Hour Microalbumin Creatinine Ratio",
"Price": 110.00,
"DiscountedPrice": 1.0,
"Type": "Test",
"TestPackageGroupId": 3,
"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": 3,
"SampleTypeList": [
{
"TestSampleTypeId": "66",
"SampleName": "24 hrs Urine",
"ColourCode": "#212DC1"
}
]
},
{
"PackageId": 936,
"PackageName": "24 Hours Urinary Phosphorous",
"Price": 15.00,
"DiscountedPrice": 1.0,
"Type": "Test",
"TestPackageGroupId": 3,
"SampleTypeList": [
{
"TestSampleTypeId": "66",
"SampleName": "24 hrs Urine",
"ColourCode": "#212DC1"
}
]
},
{
"PackageId": 937,
"PackageName": "24 Hours Urinary Potassium",
"Price": 2.00,
"DiscountedPrice": 1.0,
"Type": "Test",
"TestPackageGroupId": 3,
"SampleTypeList": [
{
"TestSampleTypeId": "66",
"SampleName": "24 hrs Urine",
"ColourCode": "#212DC1"
}
]
},
......
]}
Decoding Model for the above
import Foundation
struct PriceList {
let Success: Bool
let message: String
let Response: [ResponseList]?
}
extension PriceList:Codable
{
enum CodingKeys: String, CodingKey
{
case Success = "IsSuccess"
case message = "Message"
case Response = "ResponseData"
}
init(from decoder:Decoder) throws {
let container = try decoder.container(keyedBy:CodingKeys.self)
Success = try container.decode(Bool.self,forKey: .Success)
message = try container.decode(String.self,forKey: .message)
Response = try container.decode([ResponseList].self,forKey: .Response)
}
}
struct ResponseList
{
let packageID: Int
let packageName: String
let price, discountedPrice: Double
let type: String
let testPackageGroupID: Int
let SampleType: [SampleTypeList]?
}
extension ResponseList:Decodable
{
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"
}
init(from decoder:Decoder) throws
{
let container = try decoder.container(keyedBy:CodingKeys.self)
packageID = try container.decode(String.self,forKey: .packageID)
packageName= try container.decode(String.self,forKey: .packageName)
price= try container.decode(Double.self,forKey: .price)
discountedPrice= try container.decode(Double.self,forKey:.discountedPrice)
type= try container.decode(String.self,forKey: .type)
testPackageGroupID = try container.decode(String.self,forKey: .testPackageGroupID )
SampleType= try container.decode([SampleTypeList].self,forKey: .SampleType)
}
}
struct SampleTypeList
{
let testSampleTypeID, sampleName, colourCode: String
}
extension SampleTypeList:Codable {
enum SampleKeys: String, CodingKey {
case testSampleTypeID = "TestSampleTypeId"
case sampleName = "SampleName"
case colourCode = "ColourCode"
}
init(from decoder:Decoder) throws
{
let container = try decoder.container(keyedBy:SampleKeys.self)
testSampleTypeID = try container.decode(String.self,forKey: .testSampleTypeID )
sampleName = try container.decode(String.self,forKey: .sampleName )
colourCode = try container.decode(String.self,forKey: .colourCode)
}
}
This is the code written in playground:
var urlComponents = URLComponents()
urlComponents.scheme = "http"
urlComponents.host = "xx.xx.xxx.x"
urlComponents.path = "/api/test/home"
urlComponents.queryItems = [URLQueryItem(name: "pricelistGroupId",value: "12")]
let url = urlComponents.url
var request = URLRequest(url: url!)
request.addValue("application/json", forHTTPHeaderField:
"Accept")
request.addValue("Basic \(authToken)", forHTTPHeaderField:
"Authorization")
let task = URLSession.shared.dataTask(with: request)
{
(data, response, error) in
if let error = error
{
print("Error \(error)")
return
}
if let response = response as? HTTPURLResponse {
print("Response \(response.statusCode)")
}
if let data = data
{
let dataString = String(data:data, encoding: .utf8)
print(dataString)
let json = try? JSONDecoder().decode(PriceList.self,from:data)
print(json)
}
}
print(dataString) is printing the data. However, no data for print(json) it is showing nil in playground.
ResponseList init is stuck at 259 times (right side playground tab showing all process) whereas SampleTypeList is stuck at 346 times.
If I remove ? (optional) from [ResponseList]? and [SampleTypeList]? it showing "Cannot get unkeyed decoding container -- found null value instead."
Please, ignore typo errors.
Program is stuck at where it is finding null for eg two instances mainly
SampleTypeList = null (occurs many times in JSON) testPackageGroupID = null
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)")
}
try this, works for me:
extension ResponseList: Codable { // <-- here not Decodable
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"
}
init(from decoder:Decoder) throws {
let container = try decoder.container(keyedBy:CodingKeys.self)
packageID = try container.decode(Int.self,forKey: .packageID) // <-- here Int
packageName = try container.decode(String.self,forKey: .packageName)
price = try container.decode(Double.self,forKey: .price)
discountedPrice = try container.decode(Double.self,forKey:.discountedPrice)
type = try container.decode(String.self,forKey: .type)
testPackageGroupID = try container.decode(Int.self,forKey: .testPackageGroupID ) // <-- here Int
SampleType = try container.decode([SampleTypeList].self,forKey: .SampleType)
}
}
EDIT:
Here is the code I used to show decoding the given json data works with my answer.
import SwiftUI
import Foundation
#main
struct TestApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
struct PriceList {
let Success: Bool
let message: String
let Response: [ResponseList]?
}
extension PriceList: Codable {
enum CodingKeys: String, CodingKey {
case Success = "IsSuccess"
case message = "Message"
case Response = "ResponseData"
}
init(from decoder:Decoder) throws {
let container = try decoder.container(keyedBy:CodingKeys.self)
Success = try container.decode(Bool.self,forKey: .Success)
message = try container.decode(String.self,forKey: .message)
Response = try container.decode([ResponseList].self,forKey: .Response)
}
}
struct ResponseList {
let packageID: Int
let packageName: String
let price, discountedPrice: Double
let type: String
let testPackageGroupID: Int
let SampleType: [SampleTypeList]?
}
extension ResponseList: Codable { // <-- here not Decodable
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"
}
init(from decoder:Decoder) throws {
let container = try decoder.container(keyedBy:CodingKeys.self)
packageID = try container.decode(Int.self,forKey: .packageID) // <-- here Int
packageName = try container.decode(String.self,forKey: .packageName)
price = try container.decode(Double.self,forKey: .price)
discountedPrice = try container.decode(Double.self,forKey:.discountedPrice)
type = try container.decode(String.self,forKey: .type)
testPackageGroupID = try container.decode(Int.self,forKey: .testPackageGroupID ) // <-- here Int
SampleType = try container.decode([SampleTypeList].self,forKey: .SampleType)
}
}
struct SampleTypeList {
let testSampleTypeID, sampleName, colourCode: String
}
extension SampleTypeList:Codable {
enum SampleKeys: String, CodingKey {
case testSampleTypeID = "TestSampleTypeId"
case sampleName = "SampleName"
case colourCode = "ColourCode"
}
init(from decoder:Decoder) throws {
let container = try decoder.container(keyedBy:SampleKeys.self)
testSampleTypeID = try container.decode(String.self,forKey: .testSampleTypeID )
sampleName = try container.decode(String.self,forKey: .sampleName )
colourCode = try container.decode(String.self,forKey: .colourCode)
}
}
struct ContentView: View {
#State var priceList: PriceList?
var body: some View {
Text(priceList?.message ?? "no data")
.onAppear {
let jsonString = """
{
"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": [
{
"TestSampleTypeId": "66",
"SampleName": "24 hrs Urine",
"ColourCode": "#212DC1"
}
]
},
{
"PackageId": 1914,
"PackageName": "24 Hour Microalbumin Creatinine Ratio",
"Price": 110.00,
"DiscountedPrice": 1.0,
"Type": "Test",
"TestPackageGroupId": 3,
"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": 3,
"SampleTypeList": [
{
"TestSampleTypeId": "66",
"SampleName": "24 hrs Urine",
"ColourCode": "#212DC1"
}
]
},
{
"PackageId": 936,
"PackageName": "24 Hours Urinary Phosphorous",
"Price": 15.00,
"DiscountedPrice": 1.0,
"Type": "Test",
"TestPackageGroupId": 3,
"SampleTypeList": [
{
"TestSampleTypeId": "66",
"SampleName": "24 hrs Urine",
"ColourCode": "#212DC1"
}
]
},
{
"PackageId": 937,
"PackageName": "24 Hours Urinary Potassium",
"Price": 2.00,
"DiscountedPrice": 1.0,
"Type": "Test",
"TestPackageGroupId": 3,
"SampleTypeList": [
{
"TestSampleTypeId": "66",
"SampleName": "24 hrs Urine",
"ColourCode": "#212DC1"
}
]
}
]
}
"""
let data = jsonString.data(using: .utf8)
priceList = try? JSONDecoder().decode(PriceList.self, from: data!)
print("\n--> priceList: \(priceList) \n")
}
}
}
EDIT-2:
If you can have this in your json data:
"TestPackageGroupId": null,
"SampleTypeList": null
then try this approach to decode your json data:
struct ResponseList {
let packageID: Int
let packageName: String
let price, discountedPrice: Double
let type: String
let testPackageGroupID: Int? // <--- here optional
let SampleType: [SampleTypeList]? // <--- here optional
}
extension ResponseList: Codable { // <-- here not Decodable
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"
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy:CodingKeys.self)
packageID = try container.decode(Int.self,forKey: .packageID) // <-- here Int
packageName = try container.decode(String.self,forKey: .packageName)
price = try container.decode(Double.self,forKey: .price)
discountedPrice = try container.decode(Double.self,forKey:.discountedPrice)
type = try container.decode(String.self,forKey: .type)
// --- here
testPackageGroupID = try container.decodeIfPresent(Int.self,forKey: .testPackageGroupID)
SampleType = try container.decodeIfPresent([SampleTypeList].self,forKey: .SampleType)
}
}
Likewise for any other elements that can have null.
The following two forms of data were successfully requested.
{
"ride_fare": 1000,
"km": 7
]
}
{
"ride_fare": 1000,
"km": 7,
"options": [ 0, 1, 2]
}
However, I don't know how to request a two-dimensional associative array like the one below.
How can I request it?
{
"ride_fare": 1000,
"km": 7,
"option_fares": [
{
"price": 200,
"name": "立ち寄り",
"id": 1
}
]
}
The code that I wrote:
var options = [Any]()
for option in optionFares {
let params = [
"id" : option.id ?? 0,
"name" : option.name ?? "",
"price" : option.price ?? 0
] as [String : Any]
options.append(params)
}
let faresData = [
"id" : driverOrder.id ?? 0,
"km" : driverOrder.distance ?? 0,
"option_fares" : options,
"ride_fare" : driverOrder.ride_fare ?? 0
] as [String : Any]
First, create a struct that matches the json format you want to request.
struct Params: Codable {
let rideFare, km: Int
let optionFares: [OptionFare]
enum CodingKeys: String, CodingKey {
case rideFare = "ride_fare"
case km
case optionFares = "option_fares"
}
}
struct OptionFare: Codable {
let price: Int
let name: String
let id: Int
}
And you must create a request parameter in Moya's task.
import Moya
extension APITarget: TargetType {
var task: Task {
case .yourCaseName(let price, let name, let id, let rideFare, let km):
let encoder: JSONEncoder = JSONEncoder()
let optionFareData: [OptionFare] = []
optionFareData.append(OptionFare(price, name, id))
let paramsData = Params(rideFare, km, optionFareData)
let jsonData: Data = try! encoder.encode(paramsData)
return .requestData(jsonData)
}
}
}
I am trying to fetch a random user from an api and I created a struct called result to match the json from the api.
This is what I came up with but I am sure this is not the right way to do it!
When I run this I get [] as a result so I want to know how I can change this code in order to match the json
#State var results : result?
struct result : Codable {
var results : [user]
struct user : Codable{
var gender : String
var name : name
var location : location
var email:String
struct name : Codable{
var title : String
var first : String
var last : String
}
struct location : Codable {
let street : street
let city : String
let state : String
let country : String
let postcode : Int
struct street :Codable {
var number : String
var name : String
}
}
struct login : Codable {
var uuid : String
var username : String
var password : String
}
}
}
This is how the Json looks
{
"results": [
{
"gender": "male",
"name": {
"title": "mr",
"first": "brad",
"last": "gibson"
},
"location": {
"street": "9278 new road",
"city": "kilcoole",
"state": "waterford",
"postcode": "93027",
"coordinates": {
"latitude": "20.9267",
"longitude": "-7.9310"
},
"timezone": {
"offset": "-3:30",
"description": "Newfoundland"
}
},
"email": "brad.gibson#example.com",
"login": {
"uuid": "155e77ee-ba6d-486f-95ce-0e0c0fb4b919",
"username": "silverswan131",
"password": "firewall",
"salt": "TQA1Gz7x",
"md5": "dc523cb313b63dfe5be2140b0c05b3bc",
"sha1": "7a4aa07d1bedcc6bcf4b7f8856643492c191540d",
"sha256": "74364e96174afa7d17ee52dd2c9c7a4651fe1254f471a78bda0190135dcd3480"
},
"dob": {
"date": "1993-07-20T09:44:18.674Z",
"age": 26
},
"registered": {
"date": "2002-05-21T10:59:49.966Z",
"age": 17
},
"phone": "011-962-7516",
"cell": "081-454-0666",
"id": {
"name": "PPS",
"value": "0390511T"
},
"picture": {
"large": "https://randomuser.me/api/portraits/men/75.jpg",
"medium": "https://randomuser.me/api/portraits/med/men/75.jpg",
"thumbnail": "https://randomuser.me/api/portraits/thumb/men/75.jpg"
},
"nat": "IE"
}
],
"info": {
"seed": "fea8be3e64777240",
"results": 1,
"page": 1,
"version": "1.3"
}
}
You want to learn how to do this on your own but there are tools on the web that can easily help you create a struct from a JSON. This is a really good one.
You were close so make sure you dissect the code and notice the differences
import SwiftUI
class ResultsViewModel: ObservableObject{
let json = """
{
"results": [
{
"gender": "male",
"name": {
"title": "mr",
"first": "brad",
"last": "gibson"
},
"location": {
"street": "9278 new road",
"city": "kilcoole",
"state": "waterford",
"postcode": "93027",
"coordinates": {
"latitude": "20.9267",
"longitude": "-7.9310"
},
"timezone": {
"offset": "-3:30",
"description": "Newfoundland"
}
},
"email": "brad.gibson#example.com",
"login": {
"uuid": "155e77ee-ba6d-486f-95ce-0e0c0fb4b919",
"username": "silverswan131",
"password": "firewall",
"salt": "TQA1Gz7x",
"md5": "dc523cb313b63dfe5be2140b0c05b3bc",
"sha1": "7a4aa07d1bedcc6bcf4b7f8856643492c191540d",
"sha256": "74364e96174afa7d17ee52dd2c9c7a4651fe1254f471a78bda0190135dcd3480"
},
"dob": {
"date": "1993-07-20T09:44:18.674Z",
"age": 26
},
"registered": {
"date": "2002-05-21T10:59:49.966Z",
"age": 17
},
"phone": "011-962-7516",
"cell": "081-454-0666",
"id": {
"name": "PPS",
"value": "0390511T"
},
"picture": {
"large": "https://randomuser.me/api/portraits/men/75.jpg",
"medium": "https://randomuser.me/api/portraits/med/men/75.jpg",
"thumbnail": "https://randomuser.me/api/portraits/thumb/men/75.jpg"
},
"nat": "IE"
}
],
"info": {
"seed": "fea8be3e64777240",
"results": 1,
"page": 1,
"version": "1.3"
}
}
""".data(using: .utf8)
var result: JSONObject? {
var decoded: JSONObject? = nil
do{
decoded = try JSONDecoder().decode(JSONObject.self, from: json!)
}catch{
print(error)
}
return decoded
}
}
struct ResultsView: View {
#StateObject var vm: ResultsViewModel = ResultsViewModel()
var body: some View {
if vm.result == nil || vm.result?.results.first == nil{
Text("nil")
}else{
VStack{
Text(vm.result!.results.first!.name.first)
Text(vm.result!.results.first!.name.last)
}
}
}
}
// MARK: - JSONObject
struct JSONObject: Codable {
let results: [Result]
let info: Info
}
// MARK: - Info
struct Info: Codable {
let seed: String
let results, page: Int
let version: String
}
// MARK: - Result
struct Result: Codable {
let gender: String
let name: Name
let location: Location
let email: String
let login: Login
let dob, registered: Dob
let phone, cell: String
let id: ID
let picture: Picture
let nat: String
}
// MARK: - Dob
struct Dob: Codable {
let date: String
let age: Int
}
// MARK: - ID
struct ID: Codable {
let name, value: String
}
// MARK: - Location
struct Location: Codable {
let street, city, state, postcode: String
let coordinates: Coordinates
let timezone: Timezone
}
// MARK: - Coordinates
struct Coordinates: Codable {
let latitude, longitude: String
}
// MARK: - Timezone
struct Timezone: Codable {
let offset, timezoneDescription: String
enum CodingKeys: String, CodingKey {
case offset
case timezoneDescription = "description"
}
}
// MARK: - Login
struct Login: Codable {
let uuid, username, password, salt: String
let md5, sha1, sha256: String
}
// MARK: - Name
struct Name: Codable {
let title, first, last: String
}
// MARK: - Picture
struct Picture: Codable {
let large, medium, thumbnail: String
}
I have a struct type which lists different types which must be decoded from JSON and I cannot find any information on how to specify more than one type in my enum called CodingKeys. In the innermost dictionary sometimes one key:value pair will be [String:String] and another key:value pair will be [String:Int]
I have tried specifying just String and CodingKey as in the code snippet below but Xcode reports 2 error messages.
struct JSONSiteData : Codable {
let destinationAddresses : [String]
let originAddresses : [String]
let rows : [ [String : [[String:[[String: [String:Any]]]]]] ]
let status : String
}
enum CodingKeys : String, CodingKey {
case destinationAddresses = "destination_addresses"
case originAddresses = "origin_addresses"
case rows
case status
}
I get the following error messages from Xcode;
Type 'JSONSiteData' does not conform to protocol 'Decodable'
Type 'JSONSiteData' does not conform to protocol 'Encodable'
Here is my JSON;
{
"destination_addresses": [
"1 Dunwell Ln, Bolam, Darlington DL2 2UW, UK",
"Unnamed Road, Newton Aycliffe DL5 6QZ, UK",
"Preston Manor Farm, Preston le Skerne, Newton Aycliffe DL5 6JH, United Kingdom",
"6 Middridge Farms, Middridge, Newton Aycliffe DL5 7JQ, UK",
"1 The Gardens, Hunwick, Crook DL15 0XW, UK"
],
"origin_addresses": [
"42 Drovers Way, Dunstable LU6 1AW, UK"
],
"rows": [
{
"elements": [
{
"distance": {
"text": "220 mi",
"value": 353731
},
"duration": {
"text": "3 hours 45 mins",
"value": 13475
},
"status": "OK"
},
{
"distance": {
"text": "222 mi",
"value": 356696
},
"duration": {
"text": "3 hours 45 mins",
"value": 13471
},
"status": "OK"
},
{
"distance": {
"text": "222 mi",
"value": 358053
},
"duration": {
"text": "3 hours 46 mins",
"value": 13545
},
"status": "OK"
},
{
"distance": {
"text": "225 mi",
"value": 361421
},
"duration": {
"text": "3 hours 49 mins",
"value": 13768
},
"status": "OK"
},
{
"distance": {
"text": "229 mi",
"value": 369280
},
"duration": {
"text": "3 hours 57 mins",
"value": 14238
},
"status": "OK"
}
]
}
],
"status": "OK"
}
You can try this,
// To parse the JSON, add this file to your project and do:
//
// let jsonSiteData = try? newJSONDecoder().decode(JSONSiteData.self, from: jsonData)
import Foundation
struct JSONSiteData: Codable {
let destinationAddresses, originAddresses: [String]
let rows: [Row]
let status: String
enum CodingKeys: String, CodingKey {
case destinationAddresses = "destination_addresses"
case originAddresses = "origin_addresses"
case rows, status
}
}
struct Row: Codable {
let elements: [Element]
}
struct Element: Codable {
let distance, duration: Distance
let status: String
}
struct Distance: Codable {
let text: String
let value: Int
}
Refer this link to generate models from JSON Strings.
https://app.quicktype.io/
In terms of Codable there are no different types.
Decode these structs
struct JSONSiteData : Decodable {
let destinationAddresses : [String]
let originAddresses : [String]
let rows : [Row]
let status : String
}
struct Row : Decodable {
let elements : [Element]
}
struct Element : Decodable {
let distance : Item
let duration : Item
let status : String
}
struct Item : Decodable {
let text : String
let value : Int
}