简体   繁体   English

JSON 在 Swift 中编码

[英]JSON to Codable in Swift

I'm struggling cause I don't know how to consume this JSON because in the "weather" part of the JSON it receives [0] as key-value and I don't know how to declare it我很挣扎,因为我不知道如何使用这个 JSON,因为在 JSON 的“天气”部分,它接收 [0] 作为键值,我不知道如何声明它

{
  "coord": {
    "lon": -35.7353,
    "lat": -9.6658
  },
  "weather": [
    {
      "id": 801,
      "main": "Clouds",
      "description": "few clouds",
      "icon": "02d"
    }
  ],
  "base": "stations",
  "main": {
    "temp": 302.84,
    "feels_like": 305.59,
    "temp_min": 302.84,
    "temp_max": 302.84,
    "pressure": 1011,
    "humidity": 61
  },
  "visibility": 10000,
  "wind": {
    "speed": 7.2,
    "deg": 90
  },
  "clouds": {
    "all": 20
  },
  "dt": 1672689129,
  "sys": {
    "type": 1,
    "id": 8413,
    "country": "BR",
    "sunrise": 1672646788,
    "sunset": 1672692412
  },
  "timezone": -10800,
  "id": 3395981,
  "name": "Maceió",
  "cod": 200
}

my attempt looked like this, and it kept failing cause of the weather part.我的尝试看起来像这样,但由于天气原因一直失败。 i've tried some stuff like UUID() but none of it seens to work (maybe i'm applying it the wrong way)我已经尝试过一些像 UUID() 这样的东西,但没有一个看起来有效(也许我以错误的方式应用它)

import Foundation

struct Response: Codable {
    
    var coord: Coord
    var weather: [Weather]?
    var main: Main
    var visibility: Int
    var wind: Wind
    var rain: Rain?
    var clouds: Clouds?
    var dt: Int
    var sys: Sys
    var timezone: Int
    var id: Int
    var name: String
    var cod: Int

}

struct Coord: Codable {
    var lon: Double
    var lat: Double
}

struct WeatherBase: Codable {
    var id: String { _id }
    private var _id: String
    var base: String
    
}

struct Weather: Codable {
    var id: Int
    var main: String
    var description: String
    var icon: String
}

struct Main: Codable {
    var temp: Double
    var feels_like: Double
    var temp_min: Double
    var temp_max: Double
    var pressure: Int
    var humidity: Int
}

struct Wind: Codable {
    var speed: Double
    var deg: Int
}

struct Rain: Codable{
    var umh: Int
}

struct Clouds: Codable {
    var all: Int
}

struct Sys: Codable {
    var type: Int
    var id: Int
    var country: String
    var sunrise: Int
    var sunset: Int
    
}

I couldn't reproduce your error using your code and json object. I just remove the WeatherBase struct because it was not used in any part.我无法使用您的代码和 json object 重现您的错误。我只是删除了 WeatherBase 结构,因为它没有在任何部分中使用。 I open a playground to understand better you problem and add the following code.我打开一个游乐场以更好地了解您的问题并添加以下代码。

guard let filePath = Bundle.main.url(forResource: "filename", withExtension: "json") else { fatalError()}
let data = try Data(contentsOf: filePath)
let jsonDecoder = JSONDecoder()
jsonDecoder.keyDecodingStrategy = .useDefaultKeys
let jsonData = try? jsonDecoder.decode(Response.self, from: data)

print(token?.weather![0].description)

Result结果

Optional("few clouds")

I hope I`ve helped you.我希望我帮助了你。

As I mentioned in my answer to your previous question, you need to check the docs to determine which fields are optional and amend your code accordingly.正如我在回答您之前的问题时提到的,您需要检查文档以确定哪些字段是可选的,并相应地修改您的代码。 Note the extra var base: String property in the Response struct.请注意Response结构中额外的var base: String属性。

The following SwiftUi code shows how to access the data that is retrieved from the openweathermap server, in particular the weather info.以下SwiftUi代码显示了如何访问从openweathermap服务器检索的数据,尤其是天气信息。 Use something similar for your UIKit code.对您的 UIKit 代码使用类似的东西。

Note that you must check the index before you access the data, as shown, otherwise your app will crash.请注意,您必须在访问数据之前检查索引,如图所示,否则您的应用程序将崩溃。

struct ContentView: View {
    @State var result: Response?
    
    var body: some View {
        VStack {
            // the base property
            Text(result?.base ?? "no base").foregroundColor(.blue)
            // check index first
            if let kount = result?.weather?.count, kount > 0 {
                Text(result?.weather![0].description ?? "no data")
                Text(result?.weather![0].main ?? "no data")
                Text(result?.weather![0].icon ?? "no data")
            } else {
                Text("no data for weather[0]").foregroundColor(.red)
            }
            // or
            if let kount = result?.weather?.count, kount > 1 {
                Text(result?.weather![1].description ?? "no data")
                Text(result?.weather![1].main ?? "no data")
                Text(result?.weather![1].icon ?? "no data")
            } else {
                Text("no data for weather[1]").foregroundColor(.red)
            }
        }
         .onAppear {
             downloadJSON { error in
                 if error == nil {
                     print("success")
                     // checks
                     if let theResult = result, let kount = theResult.weather?.count, kount > 0 {
                         print("---> base: \(theResult.base)")
                         print("---> description: \(theResult.weather![0].description)")
                         print("---> main: \(theResult.weather![0].main)")
                         print("---> icon: \(theResult.weather![0].icon)")
                     }
                    // alternative checks
                    if let theResult = result, let firstWeather = theResult.weather?.first {
                        print("---> base: \(theResult.base)")
                        print("---> description: \(firstWeather.description)")
                        print("---> main: \(firstWeather.main)")
                        print("---> icon: \(firstWeather.icon)")
                    }
                 } else {
                     print("error: \(error)")
                 }
             }
         }
    }
    
    func downloadJSON(completed: @escaping (Error?) -> ()){
        let token = "YOUR-TOKEN"
        if let url = URL(string: "https://api.openweathermap.org/data/2.5/weather?appid=\(token)&q=Maceio") {
            URLSession.shared.dataTask(with: url) { data, response, error in
                if error == nil, let data = data {
                    do {
                        self.result = try JSONDecoder().decode(Response.self, from: data)
                        completed(nil)
                    }
                    catch {
                        completed(error)
                    }
                }
            }.resume()
        }
    }
}

struct Response: Codable, Identifiable {  // <-- here
    var base: String // <-- here
    var coord: Coord
    var weather: [Weather]? // <-- here
    var main: Main?
    var visibility: Int?
    var wind: Wind?
    var rain: Rain?
    var clouds: Clouds?
    var dt: Int?
    var sys: Sys?
    var timezone: Int?
    var id: Int?
    var name: String?
    var cod: Int?
}

struct Coord: Codable {
    var lon: Double?
    var lat: Double?
}
    
struct Weather: Codable, Identifiable {  // <-- here
    var id: Int
    var main: String
    var description: String
    var icon: String
}

struct Main: Codable {
    var temp: Double?
    var feels_like: Double?
    var temp_min: Double?
    var temp_max: Double?
    var pressure: Int?
    var humidity: Int?
}

struct Wind: Codable {
    var speed: Double?
    var deg: Int?
}

struct Rain: Codable{
    var umh: Int?
}

struct Clouds: Codable {
    var all: Int?
}

struct Sys: Codable {
    var type: Int?
    var id: Int?
    var country: String?
    var sunrise: Int?
    var sunset: Int?
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM