skip to Main Content

I would like to get the position data of a city from the openweathermap Geocoding API
But I have a problem with there Json struct and that the path starts with a 0

like this: 0.lat

here is an example of the JSON I get back

[
  {
    "name": "Osimo",
    "local_names": {
      "ru": "Озимо",
      "fr": "Osime",
      "it": "Osimo"
    },
    "lat": 43.4861359,
    "lon": 13.4824068,
    "country": "IT",
    "state": "Marche"
  }
]

And this is my code. I found CodingKey when I was looking up the problem but it doesn’t work in my code or I did made a mistake.

PositionData.swift

enum CodingKeys: String, CodingKey {
    case zero = "0"
}
struct PositionData: Decodable {
        let zer0: Zero
    }

struct Zero: Decodable {

But when I would like to code the path it tells me that: Value of type ‘PositionData’ has no member ‘0’

LocationManager.Swift

do {
            let decodedData = try decoder.decode(PositionData.self, from: positionData)
            print(decodedData.0.lat)
        } catch {
            print("Error in Json")

I tried to load the position data of the openweathermap Geocoding API.
Now I am not sure how to decode the JSON data with a path like this 0.lat

2

Answers


  1. There is no the path starts with a 0.

    You have to decode an array and get the item at index zero

    do {
        let decodedData = try decoder.decode([PositionData].self, from: positionData)
         print(decodedData[0].lat)  // better print(decodedData.first?.lat)
    } catch {
        print(error) // NEVER print a literal like ("Error in Json")
    }
    

    and delete

    enum CodingKeys: String, CodingKey {
        case zero = "0"
    }
    struct PositionData: Decodable {
            let zer0: Zero
        }
    
    struct Zero: Decodable {
    

    PositionData must look like

    struct PositionData: Decodable {
        let lat, lon: Double
        // ...
    }
    
    Login or Signup to reply.
  2. You could specifically send only the data at position 0 to the json decoder or your could fetch and decode the entire array and show only the data at position 0, it’s really upto you.

    Client

    class APIManager {
    
    static let shared = APIManager()
        
        func fetchWeatherData(url: URL, completionHandler: @escaping ([PositionData]?, Error?) -> Void) {
            let task = URLSession.shared.dataTask(with: url, completionHandler: { data, response, error in
                if let data {
                    do {
                        let json = try? JSONSerialization.jsonObject(with: data, options: .fragmentsAllowed) as? [String: Any]
                        if let json = json {
                            completionHandler([PositionData(json)], nil)
                        }
                    }
                } else {
                    completionHandler(nil, error)
                }
            })
            task.resume()
        }
    }
    

    Model

    struct PositionData: Decodable {
        
        var id: UUID
        var lat: Double
        var lon: Double
        
        init(_ data: [String : Any]) {
            id = UUID()
            lat = data["lat"] as? Double ?? 0
            lon = data["lon"] as? Double ?? 0
        }
    }
    

    View

    struct MyView: View {
        
        let url = URL(string: "www.weatherData.com")
        @State var weatherData: [PositionData]?
        
        var body: some View {
            VStack {
                if let weatherData {
                    if !weatherData.isEmpty {
                        Text("lat: (weatherData[0].lat), lon: (weatherData[0].lon)")
                    }
                }
            }
            .onAppear {
                if let url {
                    fetchWeather(url: url)
                }
            }
        }
    }
    

    ViewModel

    extension MyView {
        func fetchWeather(url: URL) {
            APIManager.shared.fetchWeatherData(url: url) { data, error  in
                if let data {
                    for datum in data {
                        weatherData.append(datum)
                    }
                } else {
                    print(error?.localizedDescription)
                }
            }
        }
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search