使用 JSON 解码器读取 json 文件

Using JSON Decoder to read json file

我有一个应用可以获取以下格式的天气 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()

这获取了数据,但我有 2 个问题:

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

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

而且不仅仅是描述。我该如何解决这个问题?

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

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

struct weatherApiMain: Codable {
   var temp: Double
}

我收到一个错误。

I am decoding the data for the weather description but when displaying it in the label self.currentWeather.text it displays [appName.weatherApiWeather(description: "few clouds")] and not just the description.

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

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

您应该访问数组中所需元素的描述。比如第一个:

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

我不太了解这个 API 无法告诉您为什么天气数据在数组中。您必须阅读 API 文档才能找到答案。

How do I set up the 'weatherApi' key in a structure to get the 'main' data?

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

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

auto-generated 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 中有不止一个 main,所以我不确定您需要哪一个。对于第一个,访问权限如上所示:

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。