Swift - JSONDecoder

76 Views Asked by At

I am trying to make a weather application by decoding weather information from an api. Actually, I did, it works, but there is a problem. When I type a city name it works, but another city does not decode according to the Model I type. Data comes in all kinds, but in some cities it does not decode.

Below I shared the codes I wrote in Model, Network, Controller. Can you help me where am I going wrong?

//  - Network Manager File
import Foundation
import Alamofire

struct NetworkManager {
    
    static let shared = NetworkManager()
    // Download a random story
    func downloadData(url: URL, completion: @escaping (Data?) -> ()) {
        
        AF.request(url).response { result in
            if let error = result.error {
                print(error.localizedDescription)
            } else if let data = result.data {
                let weatherModels = data
                completion(weatherModels)
            }
        }
    }
}
//- View Controller
override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        
        blueView.layer.cornerRadius = blueView.frame.width / 5
        blueView.layer.maskedCorners = [.layerMinXMaxYCorner, .layerMaxXMaxYCorner]
        collectionView.layer.cornerRadius = 30
        
        
        guard let urlString = URL(string: "https://api.weatherapi.com/v1/forecast.json?key=<api-key>=\(cityName)&days=3&aqi=no&alerts=no") else { return }
        
        NetworkManager().downloadData(url: urlString) { weatherModels in
            if let data = weatherModels {
                self.parse(data: data)
            }
        }
        
    }
    
    private func parse(data: Data) {
        
        if let weatherModel = try? JSONDecoder().decode(WeatherModel.self, from: data) {
            self.weatherModel = weatherModel
            
            guard let weatherModel = self.weatherModel else { return }
            
            DispatchQueue.main.async {
                self.cityLabel.text = weatherModel.location.name
                self.currentTemp.text = String(weatherModel.current.tempC)
                self.conditionLabel.text = weatherModel.current.condition.text.rawValue
                
                self.currentDate.text = weatherModel.location.localtime
                self.currentHumidity.text = "\(weatherModel.current.humidity)% \nHumidity"
                self.currentWind.text = "\(weatherModel.current.windKph) kph \nWind"
                self.currentFeelslike.text = "\(weatherModel.current.feelslikeC)° \nFeels Like"
                self.imageView.kf.setImage(with: URL(string: "https:\(weatherModel.current.condition.icon)"))
                
                self.collectionView.reloadData()
            }
        } else {
            print("error")
        }
    }
// - Model
import Foundation


// MARK: - WeatherModel
struct WeatherModel: Codable {
    let location: Location
    let current: Current
    let forecast: Forecast
}

// MARK: - Current
struct Current: Codable {
    let lastUpdatedEpoch: Int
    let lastUpdated: String
    let tempC: Int
    let tempF: Double
    let isDay: Int
    let condition: Condition
    let windMph, windKph: Double
    let humidity: Int
    let feelslikeC, feelslikeF: Double

    enum CodingKeys: String, CodingKey {
        case lastUpdatedEpoch = "last_updated_epoch"
        case lastUpdated = "last_updated"
        case tempC = "temp_c"
        case tempF = "temp_f"
        case isDay = "is_day"
        case condition
        case windMph = "wind_mph"
        case windKph = "wind_kph"
        case humidity
        case feelslikeC = "feelslike_c"
        case feelslikeF = "feelslike_f"
    }
}

// MARK: - Condition
struct Condition: Codable {
    let text: Text
    let icon: String
    let code: Int
}

enum Text: String, Codable {
    case clear = "Clear"
    case cloudy = "Cloudy"
    case lightRainShower = "Light rain shower"
    case overcast = "Overcast"
    case partlyCloudy = "Partly cloudy"
    case patchyRainPossible = "Patchy rain possible"
    case sunny = "Sunny"
}

// MARK: - Forecast
struct Forecast: Codable {
    let forecastday: [Forecastday]
}

// MARK: - Forecastday
struct Forecastday: Codable {
    let date: String
    let dateEpoch: Int
    let day: Day

    enum CodingKeys: String, CodingKey {
        case date
        case dateEpoch = "date_epoch"
        case day
    }
}



// MARK: - Day
struct Day: Codable {
    let maxtempC, maxtempF, mintempC, mintempF: Double
    let condition: Condition

    enum CodingKeys: String, CodingKey {
        case maxtempC = "maxtemp_c"
        case maxtempF = "maxtemp_f"
        case mintempC = "mintemp_c"
        case mintempF = "mintemp_f"
        case condition
    }
}

// MARK: - Location
struct Location: Codable {
    let name, region, country: String
    let lat, lon: Double
    let tzID: String
    let localtimeEpoch: Int
    let localtime: String

    enum CodingKeys: String, CodingKey {
        case name, region, country, lat, lon
        case tzID = "tz_id"
        case localtimeEpoch = "localtime_epoch"
        case localtime
    }
}
0

There are 0 best solutions below