3

I was trying to parse JSON through JSONDecoder and using Alamofire to fetch the data. However, when I run the app, it shows that the data couldn't be read because of the incorrect format. I have tried many things but still did not work. Any help would be appreciated. Sources are below:

VC:

class SecondTaskVC: UIViewController {

var weatherModel = [WeatherModelDecodable]()

override func viewDidLoad() {
    let url = URL(string: "https://api.openweathermap.org/data/2.5/forecast?lat=42.874722&lon=74.612222&APPID=079587841f01c6b277a82c1c7788a6c3")

    Alamofire.request(url!).responseJSON { (response) in

        let result = response.data

        do{
            let decoder = JSONDecoder()
            self.weatherModel = try decoder.decode([WeatherModelDecodable].self, from: result!) // it shows this line as a problem

            for weather in self.weatherModel {
                print(weather.city.name)
            }
        }catch let error{
            print("error in decoding",error.localizedDescription)

        }

    }
     }
   }

Data Model:

struct WeatherModelDecodable: Decodable {
  let city: CityDecodable
}

struct CityDecodable: Decodable {
  let name: String
 }
Joe Hart
  • 57
  • 8

1 Answers1

4

Actually the response structure is different from what you are trying to do at this line,

self.weatherModel = try decoder.decode([WeatherModelDecodable].self, from: result!)

The response is not an array as you can see it in a json viewer by hitting this Url in any browser. You are expecting an array of json objects but its not. So if you decode it as a single object, it will decode properly as below,

let weatherModel = try decoder.decode(WeatherModelDecodable.self, from: result!)
print(weatherModel.city.name)

So, SecondTaskVC will look like this,

class SecondTaskVC: UIViewController {

    var weatherModel: WeatherModelDecodable?

    override func viewDidLoad() {
        let url = URL(string: "https://api.openweathermap.org/data/2.5/forecast?lat=42.874722&lon=74.612222&APPID=079587841f01c6b277a82c1c7788a6c3")

        Alamofire.request(url!).responseJSON { (response) in

            let result = response.data

            do{
                let decoder = JSONDecoder()
                self.weatherModel = try decoder.decode(WeatherModelDecodable.self, from: result!)
                print(self.weatherModel!.city.name)
            }catch let error{
                print("error in decoding",error.localizedDescription)

            }

          }
        }
 }

You should decode the respective objects with the same structure you are getting in the response.

enter image description here

Kamran
  • 14,987
  • 4
  • 33
  • 51
  • Thanks, but `print(weatherModel.city.name)` this wouldn't work because it shows that `weatherModel` doesn't have member `city`. Any other ideas? – Joe Hart Jun 25 '18 at 11:17
  • It will work, you need to change the variable type from array as `var weatherModel: WeatherModelDecodable` – Kamran Jun 25 '18 at 11:18
  • now it says `Cannot assign value of type 'WeatherModelDecodable' to type 'WeatherModelDecodable.Type'` the value must be `[WeatherModelDecodable]()` what to do next? – Joe Hart Jun 25 '18 at 11:21
  • Because you still didn't update this `decode([WeatherModelDecodable].self`. See this line in answer. – Kamran Jun 25 '18 at 11:23
  • @JoeHart I included `SecondTaskVC` for your reference. – Kamran Jun 25 '18 at 11:31
  • well, basically, it says the same thing. Please, any other ideas? – Joe Hart Jun 25 '18 at 11:32
  • It shouldn't throw this error. Can you show the latest code in `SecondTaskVC` by replacing it in question? – Kamran Jun 25 '18 at 11:35
  • BTW one more thing. How do I do the thing if I want to access the List. It is an array and if I do a for loop, the model says that the List doesn't conform to protocol Decodable. Will be very happy if you help me here. – Joe Hart Jun 25 '18 at 12:03
  • I believe you have to create a `struct` for `ListItem` conforming to `Decodable` same like `CityDecodable`. and then in your `WeatherModelDecodable` you have add one more property `let list: [ListItem]` – Kamran Jun 25 '18 at 12:11