ios - 如何仅从 JSON 中获取特定值?斯威夫特 4
问题描述
我正在制作一个可以显示“白天”和“夜晚”温度的天气应用程序。为此,我需要从下面给出的 API 中获取数据。
如果您已经检查过,问题是我只需要从“3:00 AM”和“15:00”/“3:00 PM”时间获取温度,而忽略其他时间和温度。然后我必须在我的 UICollectionView 上显示它(我会自己做)
我知道它可以使用 DateFormatter 并从“dt”或“dt_txt”中获取值来完成。但是,我真的需要知道如何做到这一点。源将附上。任何帮助将不胜感激。除了我的问题之外,您注意到的任何错误也将不胜感激。:]
ViewController:注意:请仅查看 UICollectionView 功能,我添加其他功能仅供参考
class SecondTaskVC: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource {
var weatherModel: WeatherModelDecodable?
let weatherMmodel = [WeatherModelDecodable]()
var listModel = [ListDecodable]()
let textArray = ["понедельник", "вторник", "среда", "четверг", "пятница", "суббота", "воскресенье"]
@IBOutlet weak var tempLabel: UILabel!
@IBOutlet weak var cityLabel: UILabel!
@IBOutlet weak var descrpLabel: UILabel!
@IBOutlet weak var dateLabel: UILabel!
override func viewDidLoad() {
self.view.addGestureRecognizer(self.revealViewController().panGestureRecognizer())
}
// UICollectionView
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return textArray.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "WeatherCollectionViewCell", for: indexPath) as! WeatherCollectionViewCell
let urlString = "https://api.openweathermap.org/data/2.5/forecast?lat=42.874722&lon=74.612222&APPID=079587841f01c6b277a82c1c7788a6c3"
let url = URL(string: urlString)
Alamofire.request(url!).responseJSON { (response) in
let result = response.data
do{
let decoder = JSONDecoder()
self.weatherModel = try decoder.decode(WeatherModelDecodable.self, from: result!)
if let tempToConvert = self.weatherModel?.list[indexPath.row].main.temp{
// CHECK THIS, I KNOW IT IS NOT CORRECT, BUT YOU GET ME.
if let timeResult = (self.weatherModel?.list[indexPath.row].dt) {
let dateFormatter = DateFormatter()
dateFormatter.dateStyle = .none
dateFormatter.timeStyle = .short
let date = Date(timeIntervalSince1970: Double(timeResult))
if dateFormatter.string(from: date) == "3:00 AM"{
cell.dayTemp.text = String(format: "%.0f", tempToConvert - 273.15) + "°C"
self.tempLabel.text = String(format: "%.0f", tempToConvert - 273.15) + "°C"
}
if dateFormatter.string(from: date) == "3:00 PM"{
cell.dayTemp.text = "4 c"
//self.tempLabel.text = String(format: "%.0f", tempToConvert - 273.15) + "°C"
}
}
///////
}
self.cityLabel.text = self.weatherModel?.city.name
self.dateLabel.text = self.weatherModel?.list[indexPath.row].dtTxt
// displaying date and the week
if let dateResult = (self.weatherModel?.list[indexPath.row].dt) {
let date = Date(timeIntervalSince1970: TimeInterval(dateResult))
let dateFormatter = DateFormatter()
dateFormatter.timeStyle = DateFormatter.Style.medium //Set time style
dateFormatter.dateStyle = DateFormatter.Style.medium //Set date style
let localDate = dateFormatter.string(from: date)
let str = localDate.components(separatedBy: " 2018")
let dd = localDate.replacingOccurrences(of: str[0], with: self.textArray[indexPath.row])
let stringg = dd.components(separatedBy: " ")
cell.dayCollection.text = stringg[0]
print(stringg[0])
}
}catch let error{
print("error in decoding",error.localizedDescription)
}
}
return cell
}
}
数据模型:如果它很重要
struct WeatherModelDecodable: Codable {
let list: [ListDecodable]
let city: CityDecodable
enum CodinKeys: String, CodingKey{
case list = "list"
case city = "city"
}
}
struct CityDecodable: Codable {
let name: String
}
struct ListDecodable: Codable {
let dt: Int
let main: MainClassDecodable
let weather: [WeatherDecodable]
let wind: WindDecodable
let dtTxt: String
enum CodingKeys: String, CodingKey{
case dt = "dt"
case main = "main"
case weather = "weather"
case wind = "wind"
case dtTxt = "dt_txt"
}
}
struct MainClassDecodable: Codable {
let temp: Double
let tempMin: Double
let tempMax: Double
let pressure: Double
let humidity: Int
enum CodingKeys: String, CodingKey {
case temp = "temp"
case tempMin = "temp_min"
case tempMax = "temp_max"
case pressure = "pressure"
case humidity = "humidity"
}
}
struct WeatherDecodable: Codable {
let main: String
let description: String
enum CodingKeys: String, CodingKey {
case main = "main"
case description = "description"
}
}
struct WindDecodable: Codable {
let speed: Double
let deg: Double
}
如果您需要任何可以帮助我解决此问题的方法,请随时提出。
解决方案
- 首先,如果您插入
&units=metric
到 URL 查询中,您将获得学位°C
(无需转换)。 - 其次,如果您使用日期解码策略
.secondsSince1970
,您可以解码dt
为Date
(无需转换)。 - 第三,如果你使用密钥解码策略
.convertFromSnakeCase
,你可以省略所有的 CodingKeys。
这是您的结构的简化版本,省略了Decodable
名称中重复出现的 ,dt
将被解码为Date
struct WeatherModel : Decodable {
let cod : String
let list : [List]
}
struct List : Decodable {
let weather : [Weather]
let main : Main
let dt : Date
}
struct Weather : Decodable {
let main : String
let description : String
}
struct Main: Decodable {
let temp : Double
let tempMin : Double
let tempMax : Double
let pressure : Double
let humidity : Int
}
使用上述策略解码 JSON
do {
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
decoder.dateDecodingStrategy = .secondsSince1970
self.weatherModel = try decoder.decode(WeatherModel.self, from: result!)
要过滤 3AM / 3PM 日期,您首先需要从本地时间到 UTC 的差异
let utcDifference = TimeZone.current.secondsFromGMT() / 3600
现在过滤list
数组
let threeAMPMForecast = self.weatherModel.list.filter{
let hour = Calendar.current.component(.hour, from: $0.dt)
return hour == (3 + utcDifference) || hour == (15 + utcDifference)
}
print(threeAMPMForecast)
// or to print all temperatures
print(threeAMPMForecast.map{ $0.main.temp })
} catch {
print(error)
}
请在 Playground 中尝试代码。
推荐阅读
- python - 插入函数和程序执行失败
- mysql - 验证表中列的值不等于其他表中两列的值之和
- angular - RxJS switchMap 操作符不取消http请求
- c# - 将十进制格式化为长度为 9 的字符串,在 '.' 之前有 2 位数字(0 填充)和 6 之后
- git - 开发/主控的 git push 失败
- java - 等待任何完成的可调用返回值,只要它在可调用列表中完成
- reactjs - 元素类型无效,反应
- python - 使用熊猫数据框上的名称将图像从一个文件夹复制到另一个文件夹
- php - Doctrine JOIN ... ON ... 在注释中
- sql-server - 根据其他列的数据更新表别名的列数据