Пожалуйста, сбросьте NSCoding
в пользу Codable
, вы избавитесь от всего этого уродливого шаблонного кода
struct WeatherData : Decodable {
let coord : Coordinate
let cod, visibility, id : Int
let name : String
let base : String
let weather : [Weather]
let clouds: Clouds
let sys : Sys
let main : Main
let wind : Wind
let dt : Date
}
struct Coordinate : Decodable {
let lat, lon : Double
}
struct Weather : Decodable {
let id : Int
let icon : String
let main : MainEnum
let description: String
}
struct Sys : Decodable {
let type, id : Int
let sunrise, sunset : Date
let message : Double
let country : String
}
struct Main : Decodable {
let temp, tempMin, tempMax : Double
let pressure, humidity : Int
}
struct Wind : Decodable {
let speed : Double
let deg : Int
let gust : Double?
}
struct Clouds: Decodable {
let all: Int
}
enum MainEnum: String, Decodable {
case clear = "Clear"
case clouds = "Clouds"
case rain = "Rain"
}
Как видите, даты декодируются как Date
, а значения main
в Weather
декодируются как enum.
Я не знаю API NetworkProcessor
, поэтому я заменил его на традиционный URLSession
. Добавленные URLComponents
обеспечивают правильную кодировку URL, например, если city
содержит пробелы
import Foundation
class WeatherSerice {
let weatherAPIKey: String
let weatherBase = "https://api.openweathermap.org/data/2.5/weather"
init(APIKey: String) {
self.weatherAPIKey = APIKey
}
func getCurrentWeather(city: String, completion: @escaping (WeatherData?) -> Void) {
var urlComponents = URLComponents(string: weatherBase)!
let queryItems = [URLQueryItem(name: "q", value: city),
URLQueryItem(name: "appid", value: weatherAPIKey)]
urlComponents.queryItems = queryItems
if let weatherURL = urlComponents.url {
let task = URLSession.shared.dataTask(with: weatherURL) { (data, response, error) in
if let error = error { print(error); completion(nil) }
do {
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
decoder.dateDecodingStrategy = .secondsSince1970
let result = try decoder.decode(WeatherData.self, from: data!)
completion(result)
} catch {
print(error)
completion(nil)
}
}
task.resume()
}
}
}
Я рекомендую использовать новый тип Result
в Swift 5 и для возврата ошибки.
func getCurrentWeather(city: String, completion: @escaping (Result<WeatherData,Error>) -> Void) {
var urlComponents = URLComponents(string: weatherBase)!
let queryItems = [URLQueryItem(name: "q", value: city),
URLQueryItem(name: "appid", value: weatherAPIKey)]
urlComponents.queryItems = queryItems
if let weatherURL = urlComponents.url {
let task = URLSession.shared.dataTask(with: weatherURL) { (data, response, error) in
if let error = error { completion(.failure(error)) }
do {
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
decoder.dateDecodingStrategy = .secondsSince1970
let result = try decoder.decode(WeatherData.self, from: data!)
completion(.success(result))
} catch {
completion(.failure(error))
}
}
task.resume()
}
и используйте его
weatherService.getCurrentWeather(city: "London") { result in
switch result {
case .success(let result): print(result)
case .failure(let error): print(error)
}
}