使用JSON解码器读取json文件

问题描述

我有一个应用程序,它以以下格式获取天气JSON数据:

{
   "coord":{
      "lon":-1.74,"lat":60.5
   },"weather":[
      {
         "id":801,"main":"Clouds","description":"few clouds","icon":"02n"
      }
   ],"main":{
      "temp":285.17,"feels_like":275.99,"temp_min":285.17,"temp_max":285.17
   },"timezone":3600,"id":2654970,"name":"Brae","cod":200
}

我已经设置了Codable结构,如下所示:

struct weatherApi: Codable {
    
    var name:String = ""
    var base:String = ""
    var weather:[weatherApiWeather]
}

struct weatherApiWeather: Codable {
    var description: String = ""
}

用于获取JSON数据的代码如下:

let dataTask = session.dataTask(with: url!) {(data,response,error) in
    
    if error == nil && data != nil {
        let decoder = JSONDecoder()

        do {
            let currentWeather = try decoder.decode(weatherApi.self,from: data!)

            dispatchQueue.main.async { 
                self.lblCurrentWeather.text = currentWeather.weather.description //UILabel
            }
        }
        catch {
            print ("Error parsing Json")
        }

    }
}
dataTask.resume()

获取了数据,但是我有两个问题:

1-我正在解码用于天气描述的数据,但是当在标签self.currentWeather.text中显示时会显示

 [appName.weatherApiWeather(description: "few clouds")]

,而不仅仅是说明。我该如何解决

2-我似乎无法访问JSON文件密钥“ main”中保存的数据。如何在结构中设置“ weatherApi”键以获取“主要”数据?如果我使用:

struct weatherApi: Codable {
    var name:String = ""
    var base:String = ""
    var weather:[weatherApiMain]
}

struct weatherApiMain: Codable {
   var temp: Double
}

我得到一个错误

解决方法

我正在解码用于天气描述的数据,但是当在标签self.currentWeather.text中显示数据时,它将显示[appName.weatherApiWeather(description: "few clouds")] 不仅是描述。

这是因为您正在显示数组的描述:

// currentWeather.weather is an array!
self.lblCurrentWeather.text = currentWeather.weather.description

您应该改为访问数组所需元素的描述。例如,第一个:

self.lblCurrentWeather.text = currentWeather.weather.first?.description ?? "No Weather!"

我对该API知之甚少,无法告诉您为什么天气数据位于数组中。您必须阅读API文档才能找到答案。

如何在结构中设置“ weatherApi”键以获取“主要”数据?

您应该将属性命名为main,而不是weather

struct weatherApi: Codable {
    var name:String = ""
    var base:String = ""
    var main:[weatherApiMain] // notice the change in the name here!
}

自动生成的Codable实现将使用属性名称作为JSON密钥。如果需要,您仍然可以使用weather,但是必须添加一个CodingKeys枚举:

struct weatherApi: Codable {
    var name:String = ""
    var base:String = ""
    var weather:[weatherApiMain]
    enum CodingKeys: String,CodingKey {
        case name = "name"
        case base = "base"
        case weather = "main"
    }
}
,

第一个问题- 由于天气是一个数组,因此此行要求提供数组的描述,看来:

self.lblCurrentWeather.text = currentWeather.weather.description

要获得描述,应标识数组中的特定元素,如下所示:

self.lblCurrentWeather.text = currentWeather.weather[0].description

第二个问题-

上面的JSON中有多个主要版本,因此我不确定您需要哪个。对于第一个,访问将类似于上面:

anotherLabel.text = currentWeather.weather[0].main

对于其他主要模型,需要更新模型:

struct weatherApi: Codable {
    let main:Main
    var name:String = ""
    var base:String = ""
    var weather:[weatherApiMain]
}

struct Main: Codable {
   let temp: Double
}

然后访问main的内容是这样的:

yetAnotherLabel.text = currentWeather.main.temp

此外,可以将模型的每个属性分配为let而不是var。