Reputation: 39
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
Upvotes: 0
Views: 117
Reputation: 718
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)
}
}
}
}
Upvotes: 1
Reputation: 285072
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
// ...
}
Upvotes: 1