Home > front end >  Can not display properly data in array in nested complex Json with Swift
Can not display properly data in array in nested complex Json with Swift

Time:07-05

I'm tring to display in a Text view a nested part of a json content but I'm not able to do it correctly. For example I can't display properly the response of [Connector], any thoughts ?

Here is my struct :

import Foundation
import SwiftUI

// MARK: - StationDataApi
struct StationDataApi: Codable {
    var summary: Summary
    var results: [Result]
    
    enum CodingKeys: String, CodingKey {
        case summary = "summary"
        case results = "results"
    }
}

// MARK: - Result
struct Result: Codable {
    var type: ResultType
    var id: String
    var score: Double
    var dist: Double
    var info: String
    var poi: Poi
    var address: Address
    var position: GeoBias
    var viewport: Viewport
    var entryPoints: [EntryPoint]
    var chargingPark: ChargingPark
    var dataSources: DataSources?
    
    enum CodingKeys: String, CodingKey {
        case type = "type"
        case id = "id"
        case score = "score"
        case dist = "dist"
        case info = "info"
        case poi = "poi"
        case address = "address"
        case position = "position"
        case viewport = "viewport"
        case entryPoints = "entryPoints"
        case chargingPark = "chargingPark"
        case dataSources = "dataSources"
    }
}

// MARK: - Address
struct Address: Codable {
    var streetName: String
    var municipality: Country
    var countrySubdivision: Country
    var postalCode: String
    var countryCode: CountryCode
    var country: Country
    var countryCodeIso3: CountryCodeIso3
    var freeformAddress: String
    var localName: Country
    var streetNumber: String?
    var municipalitySubdivision: String?
    
    enum CodingKeys: String, CodingKey {
        case streetName = "streetName"
        case municipality = "municipality"
        case countrySubdivision = "countrySubdivision"
        case postalCode = "postalCode"
        case countryCode = "countryCode"
        case country = "country"
        case countryCodeIso3 = "countryCodeISO3"
        case freeformAddress = "freeformAddress"
        case localName = "localName"
        case streetNumber = "streetNumber"
        case municipalitySubdivision = "municipalitySubdivision"
    }
}

enum Country: String, Codable {
    case luxembourg = "Luxembourg"
}

enum CountryCode: String, Codable {
    case lu = "LU"
}

enum CountryCodeIso3: String, Codable {
    case lux = "LUX"
}

// MARK: - ChargingPark
struct ChargingPark: Codable {
    var connectors: [Connector]
    
    enum CodingKeys: String, CodingKey {
        case connectors = "connectors"
    }
}

// MARK: - Connector
struct Connector: Codable {
    var connectorType: String
    var ratedPowerKw: Int
    var voltageV: Int
    var currentA: Int
    var currentType: CurrentType
    
    enum CodingKeys: String, CodingKey {
        case connectorType = "connectorType"
        case ratedPowerKw = "ratedPowerKW"
        case voltageV = "voltageV"
        case currentA = "currentA"
        case currentType = "currentType"
    }
}

enum CurrentType: String, Codable {
    case ac3 = "AC3"
    case dc = "DC"
}

// MARK: - DataSources
struct DataSources: Codable {
    var chargingAvailability: ChargingAvailability
    
    enum CodingKeys: String, CodingKey {
        case chargingAvailability = "chargingAvailability"
    }
}

// MARK: - ChargingAvailability
struct ChargingAvailability: Codable {
    var id: String
    
    enum CodingKeys: String, CodingKey {
        case id = "id"
    }
}

// MARK: - EntryPoint
struct EntryPoint: Codable {
    var type: EntryPointType
    var position: GeoBias
    
    enum CodingKeys: String, CodingKey {
        case type = "type"
        case position = "position"
    }
}

// MARK: - GeoBias
struct GeoBias: Codable {
    var lat: Double
    var lon: Double
    
    enum CodingKeys: String, CodingKey {
        case lat = "lat"
        case lon = "lon"
    }
}

enum EntryPointType: String, Codable {
    case main = "main"
}

// MARK: - Poi
struct Poi: Codable {
    var name: String
    var phone: String?
    var categorySet: [CategorySet]
    var categories: [Query]
    var classifications: [Classification]
    
    enum CodingKeys: String, CodingKey {
        case name = "name"
        case phone = "phone"
        case categorySet = "categorySet"
        case categories = "categories"
        case classifications = "classifications"
    }
}

enum Query: String, Codable {
    case electricVehicleStation = "electric vehicle station"
}

// MARK: - CategorySet
struct CategorySet: Codable {
    var id: Int
    
    enum CodingKeys: String, CodingKey {
        case id = "id"
    }
}

// MARK: - Classification
struct Classification: Codable {
    var code: Code
    var names: [Name]
    
    enum CodingKeys: String, CodingKey {
        case code = "code"
        case names = "names"
    }
}

enum Code: String, Codable {
    case electricVehicleStation = "ELECTRIC_VEHICLE_STATION"
}

// MARK: - Name
struct Name: Codable {
    var nameLocale: NameLocale
    var name: Query
    
    enum CodingKeys: String, CodingKey {
        case nameLocale = "nameLocale"
        case name = "name"
    }
}

enum NameLocale: String, Codable {
    case enUs = "en-US"
}

enum ResultType: String, Codable {
    case poi = "POI"
}

// MARK: - Viewport
struct Viewport: Codable {
    var topLeftPoint: GeoBias
    var btmRightPoint: GeoBias
    
    enum CodingKeys: String, CodingKey {
        case topLeftPoint = "topLeftPoint"
        case btmRightPoint = "btmRightPoint"
    }
}

// MARK: - Summary
struct Summary: Codable {
    var query: Query
    var queryType: String
    var queryTime: Int
    var numResults: Int
    var offset: Int
    var totalResults: Int
    var fuzzyLevel: Int
    var geoBias: GeoBias
    
    enum CodingKeys: String, CodingKey {
        case query = "query"
        case queryType = "queryType"
        case queryTime = "queryTime"
        case numResults = "numResults"
        case offset = "offset"
        case totalResults = "totalResults"
        case fuzzyLevel = "fuzzyLevel"
        case geoBias = "geoBias"
    }

Here is an extract of the Json response :

{
    "summary": {
        "query": "electric vehicle station",
        "queryType": "NON_NEAR",
        "queryTime": 130,
        "numResults": 10,
        "offset": 0,
        "totalResults": 232894,
        "fuzzyLevel": 1,
        "geoBias": {
            "lat": 49.588056,
            "lon": 6.104167
        }
    },
    "results": [
        {
            "type": "POI",
            "id": "442009000702915",
            "score": 8.495806694,
            "dist": 357.116545666857,
            "info": "search:ev:442009000702915",
            "poi": {
                "name": "Chargy Luxembourg Place de Roedgen",
                "phone": " 352 800 62 020",
                "categorySet": [
                    {
                        "id": 7309
                    }
                ],
                "categories": [
                    "electric vehicle station"
                ],
                "classifications": [
                    {
                        "code": "ELECTRIC_VEHICLE_STATION",
                        "names": [
                            {
                                "nameLocale": "en-US",
                                "name": "electric vehicle station"
                            }
                        ]
                    }
                ]
            },
            "address": {
                "streetName": "Place de Roedgen",
                "municipality": "Luxembourg",
                "countrySubdivision": "Luxembourg",
                "postalCode": "L-2432",
                "countryCode": "LU",
                "country": "Luxembourg",
                "countryCodeISO3": "LUX",
                "freeformAddress": "Place de Roedgen, Luxembourg, L-2432",
                "localName": "Luxembourg"
            },
            "position": {
                "lat": 49.59111,
                "lon": 6.1057
            },
            "viewport": {
                "topLeftPoint": {
                    "lat": 49.59201,
                    "lon": 6.10431
                },
                "btmRightPoint": {
                    "lat": 49.59021,
                    "lon": 6.10709
                }
            },
            "entryPoints": [
                {
                    "type": "main",
                    "position": {
                        "lat": 49.59104,
                        "lon": 6.10555
                    }
                }
            ],
            "chargingPark": {
                "connectors": [
                    {
                        "connectorType": "IEC62196Type2Outlet",
                        "ratedPowerKW": 22,
                        "voltageV": 400,
                        "currentA": 32,
                        "currentType": "AC3"
                    }
                ]
            },
            "dataSources": {
                "chargingAvailability": {
                    "id": "442009000702915"
                }
            }
        }

Here is my Network code :


func loadData() async{
        
        guard let url = Bundle.main.url(forResource: "response", withExtension: "json")
        else {
            print("Json file not found")
            return
        
        
        }
        
        
        
        do {
            let (data, _) = try await URLSession.shared.data(from: url)
            
            if let decodedResponse = try? JSONDecoder().decode(StationDataApi.self, from: data) {
                results=decodedResponse.results
            }
            
            
            
        } catch {
            print("Invalid data")
            
        }
    }

Here is the my View :

struct StationView: View {
    @State private var results : [Result] = []
    
    var body: some View {
        NavigationView {
            List (results, id: \.id){item in
                NavigationLink(destination: DetailStationView(stationItem: item)){
                VStack(alignment: .leading) {
                    Text(item.chargingPark.connectors.description)
                }
                    }
                
                
            }
        }
        
        .navigationTitle("Fetch")
        .task {
            await loadData()
        }
    }

That is the result that I get. I wanted to display it properly not like a raw json content

CodePudding user response:

connectors is an array of Connector, and so you need to decide which array element you want to display. For example all elements, such as:

 VStack(alignment: .leading) {
     ForEach(item.chargingPark.connectors, id: \.self) { conector in
        Text("connectorType: \(conector.connectorType)")
        Text("PowerKw: \(conector.ratedPowerKw)")
        Text("voltageV: \(conector.voltageV)")
        Text("currentA: \(conector.currentA)")
        Text("currentType: \(conector.currentType.rawValue)")
     }
 }

or the first one as in this example:

 VStack(alignment: .leading) {
     Text("\(item.chargingPark.connectors.first?.ratedPowerKw ?? 0)")
     Text("\(item.chargingPark.connectors.first?.voltageV ?? 0)")
     Text("\(item.chargingPark.connectors.first?.currentA ?? 0)")
     Text("\(item.chargingPark.connectors.first?.currentType.rawValue ?? "")")
 }

Adjust the code and display to your specific needs. Note you may need to use struct Connector: Codable, Hashable {...} or make Connector Identifiable.

  • Related