Как декодировать массив значений JSON в словаре, когда я хочу получить только определенные значения c в словаре? - PullRequest
0 голосов
/ 26 января 2020

Я пытаюсь получить конкретную c информацию из JSON ниже в разделе "список".

Образец JSON

{
    city =     {
        coord =         {
            lat = "37.323";
            lon = "-122.0322";
        };
        country = US;
        id = 5341145;
        name = Cupertino;
        population = 58302;
        sunrise = 1579965395;
        sunset = 1580001833;
        timezone = "-28800";
    };
    cnt = 40;
    cod = 200;
    list =     (
                {
            clouds =             {
                all = 99;
            };
            dt = 1580018400;
            "dt_txt" = "2020-01-26 06:00:00";
            main =             {
                "feels_like" = "286.89";
                "grnd_level" = 1011;
                humidity = 78;
                pressure = 1020;
                "sea_level" = 1020;
                temp = "287.29";
                "temp_kf" = "-0.68";
                "temp_max" = "287.97";
                "temp_min" = "287.29";
            };
            sys =             {
                pod = n;
            };
            weather =             (
                                {
                    description = "overcast clouds";
                    icon = 04n;
                    id = 804;
                    main = Clouds;
                }
            );
            wind =             {
                deg = 183;
                speed = "0.77";
            };
        },
                {
            clouds =             {
                all = 88;
            };
            dt = 1580029200;
            "dt_txt" = "2020-01-26 09:00:00";
            main =             {
                "feels_like" = "286.55";
                "grnd_level" = 1011;
                humidity = 91;
                pressure = 1020;
                "sea_level" = 1020;
                temp = "286.64";
                "temp_kf" = "-0.51";
                "temp_max" = "287.15";
                "temp_min" = "286.64";
            };
            rain =             {
                3h = "1.88";
            };
            sys =             {
                pod = n;
            };
            weather =             (
                                {
                    description = "light rain";
                    icon = 10n;
                    id = 500;
                    main = Rain;
                }
            );
            wind =             {
                deg = 140;
                speed = "1.04";
            };
        },

Однако я запутался о том, как структурировать мои объекты и декодировать JSON, чтобы получить нужные мне значения. Вот мой класс Codable

class FiveDayWeatherInformation: Codable {

    struct Weather: Codable {
        var description: String
        var icon: String

        enum CodingKeys: String, CodingKey {
            case description
            case icon
        }
    }

    struct Main: Codable {
        var temp: Double

        enum CodingKeys: String, CodingKey {
            case temp
        }
    }

    struct ThreeHourItem: Codable {
        var dateText: String
        var weather: Weather
        var main: Main

        enum CodingKeys: String, CodingKey {
            case main
            case dateText = "dt_txt"
            case weather
        }
    }

    struct RootList: Codable {
        let list: [[String:ThreeHourItem]]

        enum CodingKeys: String, CodingKey {
            case list
        }
    }

    var rootList: RootList

    enum CodingKeys: String, CodingKey {
        case rootList = "list"
    }

    required public init(from decoder: Decoder) throws {
        let values = try decoder.container(keyedBy: CodingKeys.self)
        self.rootList = try values.decode(RootList.self, forKey: .rootList)
    }
}

И именно здесь я пытаюсь получить значения

    func fetchFiveDayForecastForCoordinates(latitude: CLLocationDegrees, longitude: CLLocationDegrees, completion: @escaping (_ weatherForecasts:[FiveDayWeatherInformation]?, Error?) -> Void) {
        // to do
        let url = URL(string: "http://api.openweathermap.org/data/2.5/forecast?lat=\(latitude)&lon=\(longitude)&APPID=APPID")
        let urlRequest = URLRequest(url: url!)
        let task = URLSession.shared.dataTask(with: urlRequest) { (data, response, error) in
            guard let data = data, error == nil else {
                completion(nil, APIError.apiServiceError)
                return
            }

            do {
                let forecast = try JSONDecoder().decode(FiveDayWeatherInformation.RootList.self, from:data)
                print(forecast)
            } catch {
                print(error)
            }
        }
        task.resume()
    }

Однако я продолжаю получать это предупреждение.

keyNotFound(CodingKeys(stringValue: "main", intValue: nil), Swift.DecodingError.Context(codingPath: [CodingKeys(stringValue: "list", intValue: nil), _JSONKey(stringValue: "Index 0", intValue: 0), _JSONKey(stringValue: "clouds", intValue: nil)], debugDescription: "No value associated with key CodingKeys(stringValue: \"main\", intValue: nil) (\"main\").", underlyingError: nil))

I Полагаю, я неправильно структурировал свой класс Codable, но не могу понять, почему.

1 Ответ

1 голос
/ 26 января 2020

Значение ключа main в list является массивом. Измените структуры на

struct RootList : Decodable {
    let list : [List]
}

struct List : Decodable {
    let main : Main
    let weather : [Weather]
    let dateText : String

    enum CodingKeys: String, CodingKey { case main, dateText = "dtTxt", weather }
}

struct Weather : Decodable {
    let icon : String
    let description: String
}

struct Main : Decodable {
    let temp : Double
}

Действительно ли ключ dt_txt? Я получаю dtTxt

...