0

I'm parsing weather JSON using Swift 4 Decodable, and i have an issue with array data. I'm think i may be a bit wrong with model (because there are bunch of decodable structs), please help.

JSON Data from the weather API:

{"coord":{"lon":-43.21,"lat":-22.9},"weather":[{"id":800,"main":"Clear","description":"clear sky","icon":"01d"}],
"base":"stations","main":{"temp":299.37,"pressure":1008,"humidity":51,"temp_min":296.15,"temp_max":302.15},
"visibility":10000,"wind":{"speed":4.1,"deg":320},"clouds":{"all":0},
"dt":1510909200,"sys":{"type":1,"id":4565,"message":0.0023,"country":"BR","sunrise":1510905615,
"sunset":1510953350},"id":3451190,"name":"Rio de Janeiro","cod":200}

Model:

struct WeatherData:Decodable {
let coord:CoordDict?
let weather:[WeatherArr]?
let base: String?
let main:MainDict?
let visibility:Int?
let wind:WindDict?
let clouds:CloudsDict?
let dt:Int?
let sys:SysDict?
let id:Int?
let name:String?
let cod:Int?}

struct CoordDict:Decodable {
let lon: Double?
let lat: Double?}

struct WeatherArr:Decodable {
let id: Int?
let main:String?
let description:String?
let icon: String?}

struct MainDict:Decodable {
let temp:Double?
let pressure:Double?
let humidity:Int?
let temp_min:Double?
let temp_max:Double?
let sea_level:Double?
let grnd_level:Double?}

struct WindDict:Decodable {
let speed:Double?
let deg:Double?}

struct CloudsDict:Decodable {
let all: Int?}

struct SysDict:Decodable {
let type:Int?
let id:Int?
let message:Double?
let country:String?
let sunrise:Int?
let sunset:Int?}

Parsing JSON data using JSONDecoder:

    let jsonUrlString = ("https://api.openweathermap.org/data/2.5/weather?lat=\(lat!)&lon=\(lon!)&APPID=\(apikey)")

    guard let url = URL(string: jsonUrlString) else { return }

    URLSession.shared.dataTask(with: url) { (data, response, err) in

        //check err
        if err != nil {
            print("Error:\(String(describing: err))")
        }

        guard let data = data else { return }
        //do stuff

        do {

            let weatherData = try JSONDecoder().decode(WeatherData.self, from: data)

            print(weatherData.name, weatherData.weather)

   //Here i can't parse the weather Array, and get xcode error

     if let wArr = weatherData.weather! as? Array<AnyObject> {
                if let weatherIcon = wArr["icon"] {
                  icon = weatherIcon
                    }
                }
        } catch let jsonErr {
            print("Error:\(jsonErr)")
        }

        }.resume()//URLSession

ERROR msg: Cannot subscript a value of type 'Array' with an index of type 'String'.

How can i fix this? How can i parse weather array elements?

5
  • The error is pretty clear. An array is index based, it has to be subscripted with an Int. Rather than a dictionary which is key based, it has to be subscripted with a String. By the way: openweathermap sends very reliable data. It's nonsensical to declare any property carelessly as optional. Commented Nov 17, 2017 at 10:40
  • It's clear. But in this case i have an issue with '[weatherArr]' type, in main weather struct. Cast from '[weatherArr]' to any unrelated type Array or Dictionary always fails. I have no idea how to make it properly in this case. Commented Nov 17, 2017 at 10:58
  • [weatherArr] is [weatherArr] (by the way structs are supposed to start with a capital letter), there's no need to cast a concrete type to a more unspecified one. Remove the type cast and get the first element with [0] or with first and optional binding. Commented Nov 17, 2017 at 11:01
  • Vadian, thank you for your patience. Well... the [weatherArr] contain only 1 element, it's a struct, it's not a surprise. Please give me advice, how can i get/parse the data from this struct further?? Please check the screenshot imgur.com/a/MpnIM Commented Nov 17, 2017 at 11:48
  • I wrote an answer. Commented Nov 17, 2017 at 11:54

1 Answer 1

2

Declare weather in the WeatherData struct as non-optional. There is always a weather

let weather : [WeatherArr]

Get the first item if the array and the icon

if let currentWeather = weatherData.weather.first {
   if let weatherIcon = currentWeather.icon  {
      print(weatherIcon)
   }
}
Sign up to request clarification or add additional context in comments.

3 Comments

I mean to declare weather in the WeatherData struct as non-optional (remove the question mark)
Oh, silly me, we are dealing with structs. I updated the answer.
Well Done! Thank you very much!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.