2017-10-08 563 views
1

我目前正在尝试使用来自https://openweathermap.org的JSON制作天气应用程序,但我在JSON文件中遇到了天气部分问题。我不知道如何访问对象内的'id'值。在Swift 4中使用复杂和嵌套数据进行JSON解析

{ 
    "base": "stations", 
    "clouds": { 
    "all": 36 
    }, 
    "cod": 200, 
    "coord": { 
    "lat": 51.51, 
    "lon": 
     -0.13 
    }, 
    "dt": 1507497600, 
    "id": 2643743, 
    "main": { 
    "humidity": 82, 
    "pressure": 1021, 
    "temp": 10.65, 
    "temp_max": 13, 
    "temp_min": 9 
    }, 
    "name": "London", 
    "sys": { 
    "country": "GB", 
    "id": 5091, 
    "message": 0.0036, 
    "sunrise": 1507443264, 
    "sunset": 1507483213, 
    "type": 1 
    }, 
    "visibility": 10000, 
    "weather": [{ 
    "description": "scattered clouds", 
    "icon": "03n", 
    "id": 802, 
    "main": "Clouds" 
    }], 
    "wind": { 
    "deg": 200, 
    "speed": 1.5 
    } 
} 

我怎么能够在那里获得数据。在我的SWIFT代码,我使用的是符合新的“可编码的”协议在迅速4.

// all structures for the data 
struct CurrentLocalWeather: Codable { 
    let base: String 
    let clouds: clouds 
    let cod: Int 
    let coord: coord 
    let dt: Int 
    let id: Int 
    let main: main 
    let name: String 
    let sys: sys 
    let visibility: Int 
    let weather: [weather] 
    let wind: wind 
    } 

struct clouds: Codable { 
    let all: Int 
} 

struct coord: Codable { 
    let lat: Double 
    let lon: Double 
} 

struct main: Codable { 
    let humidity: Double 
    let pressure: Double 
    let temp: Double 
    let temp_max: Double 
    let temp_min: Double 
} 

struct sys: Codable { 
    let country: String 
    let id: Int 
    let message: Double 
    let sunrise: Double 
    let sunset: Double 
    let type: Int 
} 

struct weather: Codable { 
    let description: String 
    let icon: String 
    let id: Int 
    let main: String 
} 

struct wind: Codable { 
    let deg: Double 
    let speed: Double 
} 

// Get data from weather server 
func getCurrentWeatherData() { 

     let jsonUrlString = "https://api.openweathermap.org/data/2.5/weather?id=2643743&units=metric&APPID=fdf04e9483817ae2fa77048f7e6705e8" 

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

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

      guard let data = data else { return } 

      do { 
       let decoder = JSONDecoder() 
       decoder.dateDecodingStrategy = .iso8601 

       let json = try decoder.decode(CurrentLocalWeather.self, from: data) 

       print("Data Successfully Retrieved!\nServer Response: \(json.cod)\nLocation: \(json.name)") 

       DispatchQueue.main.async() { 
        // Any of the following allows me to access the data from the JSON 
        self.locationLabel.text = "\(json.name)" 
        self.temperatureLabel.text = "Currently: \(json.main.temp)ºC" 
        self.highTemperatureLabel.text = "High: \(json.main.temp_max)ºC" 
        self.lowTemperatureLabel.text = "Low: \(json.main.temp_min)ºC" 
        self.sunriseLabel.text = "\(self.convertFromUnixToNormal(time: json.sys.sunrise))" 
        self.sunsetLabel.text = "\(self.convertFromUnixToNormal(time: json.sys.sunset))" 
        self.humidityLabel.text = "Humidity: \(json.main.humidity)%" 
        self.pressureLabel.text = "Pressure: \(json.main.pressure) hPa" 
        self.windSpeedLabel.text = "Wind Speed: \(json.wind.speed) km/h" 


       } 
      } catch let jsonErr { 
       print("Error: \(jsonErr)") 
      } 

     }.resume() 
    } 

回答

2

您需要正确识别你的JSON字符串,并提供一切必要的结构进行解码。只要看一眼提供的JSON,你可以有必要的结构的一个想法,它正确解码:

struct CurrentLocalWeather: Codable { 
    let base: String 
    let clouds: Clouds 
    let cod: Int 
    let coord: Coord 
    let dt: Int 
    let id: Int 
    let main: Main 
    let name: String 
    let sys: Sys 
    let visibility: Int 
    let weather: [Weather] 
    let wind: Wind 
} 
struct Clouds: Codable { 
    let all: Int 
} 
struct Coord: Codable { 
    let lat: Double 
    let lon: Double 
} 
struct Main: Codable { 
    let humidity: Int 
    let pressure: Int 
    let temp: Double 
    let tempMax: Int 
    let tempMin: Int 
    private enum CodingKeys: String, CodingKey { 
     case humidity, pressure, temp, tempMax = "temp_max", tempMin = "temp_min" 
    } 
} 
struct Sys: Codable { 
    let country: String 
    let id: Int 
    let message: Double 
    let sunrise: UInt64 
    let sunset: UInt64 
    let type: Int 
} 
struct Weather: Codable { 
    let description: String 
    let icon: String 
    let id: Int 
    let main: String 
} 
struct Wind: Codable { 
    let deg: Int 
    let speed: Double 
} 

let weatherData = Data(""" 
{"base" : "stations", 
"clouds": { "all": 36 }, 
"cod" : 200, 
"coord" : { "lat": 51.51, 
      "lon": -0.13}, 
"dt": 1507497600, 
"id": 2643743, 
"main": { 
     "humidity": 82, 
     "pressure": 1021, 
     "temp": 10.65, 
     "temp_max": 13, 
     "temp_min": 9}, 
"name": "London", 
"sys": { 
     "country": "GB", 
     "id": 5091, 
     "message": 0.0036, 
     "sunrise": 1507443264, 
     "sunset": 1507483213, 
     "type": 1 }, 
"visibility": 10000, 
"weather": [{ 
    "description": "scattered clouds", 
    "icon": "03n", 
    "id": 802, 
    "main": "Clouds"}], 
"wind": { 
    "deg": 200, 
    "speed": 1.5 
    } 
} 
""".utf8) 

let decoder = JSONDecoder() 

do { 
    let currentLocalWeather = try decoder.decode(CurrentLocalWeather.self, from: weatherData) 
    print(currentLocalWeather) // "CurrentLocalWeather(base: "stations", clouds: __lldb_expr_367.Clouds(all: 36), cod: 200, coord: __lldb_expr_367.Coord(lat: 51.509999999999998, lon: -0.13), dt: 1507497600, id: 2643743, main: __lldb_expr_367.Main(humidity: 82, pressure: 1021, temp: 10.65, temp_max: 13, temp_min: 9), name: "London", sys: __lldb_expr_367.Sys(country: "GB", id: 5091, message: 0.0035999999999999999, sunrise: 1507443264, sunset: 1507483213, type: 1), visibility: 10000, weather: [__lldb_expr_367.Weather(description: "scattered clouds", icon: "03n", id: 802, main: "Clouds")], wind: __lldb_expr_367.Wind(deg: 200, speed: 1.5))\n" 
} catch { 
    print(error) 
} 
+0

感谢。我可以获取数据并打印时没有问题,但我不明白如何在JSON文件中获取存储在名为天气的对象下的数据。例如,如果我想要获得风速,我只需编写json.wind.speed代码,但要获取天气编号,我不能执行json.weather.id,因为数据是使用字典存储在数组中的。我想从这里获取数据 - > weather:[Weather.weather(description:“阴云”,图标:“04d”,id:804,main:“Clouds”)] –

+0

'json.weather.first? .whatever' –

+0

顺便说一句,它不是一个字典数组,它是一个天气对象数组 –

0

您需要在您的JSON,例如定义类型的自定义类型的结构天气,云,坐标等。我建议看看documentation中的示例。

在此示例中,Landmark类型具有Coordinate类型的“位置”属性。您甚至可以在示例中使用Coordinate类型作为JSON对象中的坐标属性。但是,您需要使用documentation中描述的CodingKey协议来提供正确的密钥。例如,您的Coordinate类型可能是这样的:

struct Coordinate: Codable { 
    var latitude: Double 
    var longitude: Double 

    enum CodingKeys: String, CodingKey { 
     case latitude = "lat" 
     case longitude = "lon" 
    } 
}