如何使用 JSON.serializer 在 Swift 中解析 JSON

Posted

技术标签:

【中文标题】如何使用 JSON.serializer 在 Swift 中解析 JSON【英文标题】:How to parse JSON in Swift using JSON.serializer 【发布时间】:2020-04-03 18:23:29 【问题描述】:

我正在学习在 Xcode 中解析 OpenWeather API 并且有点困惑。 因此,我必须发出 get 请求以接收来自 OpenWeather 的天气报告,然后将其显示在我准备的标签中。

我有带标签网点的主要 VC

class ViewController: UIViewController  
   @IBOutlet weak var weatherDescriptionlabel: UILabel!
   @IBOutlet weak var cityLabel: UILabel!
   @IBOutlet weak var currentWeatherLabel: UILabel!

   var Data: [DataClass] = []
   var cityName: String = ""
   var currentWeather: Int = 0
   var weatherDescription: String = ""

    override func viewDidLoad() 
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        dataLoader().loadData()
    

我有一个单独的类来“准备”用于传输的 JSON 数据

class WeatherDataClass 

let cityName: String
let currentWeather: Int
let weatherDescription: String

init (data: NSDictionary)
    let cityName = data["name"] as? String
    let currentWeather = data["temp"] as? String
    let weatherDescription = data["description"] as? String
    self.cityName = cityName!
    self.currentWeather = Int(currentWeather!)!
    self.weatherDescription = weatherDescription!


还有一个调用 API 的 DataLoader

protocol dataLoaderDelegate
    func load( data: [WeatherDataClass] ) 

class dataLoader

    var delegate: dataLoaderDelegate?

    var Url = URL(string: "http://api.openweathermap.org/data/2.5/weather?q=London,uk&APPID=f2a7ca3bd41dfa2efab0ad667aafe1df")!

    func loadData()

        let url = Url
        let request = URLRequest(url: url)
        let task = URLSession.shared.dataTask(with: request)  data, response, error in
            if let data = data,
                let json = try? JSONSerialization.jsonObject(with: data, options: .allowFragments),
            let jsonDict = json as? NSDictionary
                var weather: [WeatherDataClass] = []
                for (_,data) in jsonDict where data is NSDictionary
                    if let x = WeatherDataClass(data: data as! NSDictionary)
                        weather.append(x)
                    
                
                self.delegate?.load(data: weather)

             
        task.resume()


    

问题是来自 JSONdict 的数据没有包装到 NSDictionary 它仍然是 Any 并给我一个错误

我做错了什么? 提前感谢您的帮助

【问题讨论】:

我建议看看:swiftjson.guide “它仍然是任何并给我错误” - 请分享您遇到的错误。 请搜索。有很多相关问题how to parse openweathermap。并且根本不要在 Swift 中使用 NS... 集合类型。您丢弃了导致问题的类型信息。 【参考方案1】:

检查您的请求后,我建议使用JSONDecoder 和Codable 协议。

你应该首先创建你的结构并适应 Codable 协议:

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


struct Weather: Codable 
    let id: Int
    let icon: String
    let main: String
    let description: String


struct Main: Codable 
    let temp: Double
    let feelsLike: Double
    let tempMin: Double
    let tempMax: Double
    let pressure: Double
    let humidity: Int


struct Wind: Codable 
    let speed: Int
    let deg: Int


struct Clouds: Codable 
    let all: Int


struct Sys: Codable 
    let type: Int
    let id: Int
    let country: String
    let sunrise: Int
    let sunset: Int


struct WeatherQuery: Codable 
    let coord: Coord
    let weather: [Weather]
    let base: String
    let main: Main
    let visibility: Int
    let wind: Wind

    let clouds: Clouds
    let dt: Int
    let sys: Sys
    let timezone: Int
    let id: Int
    let name: String
    let cod: Int

完成后,您可以执行以下操作:

let request = URLRequest(url: URL(string: "http://api.openweathermap.org/data/2.5/weather?q=London,uk&APPID=f2a7ca3bd41dfa2efab0ad667aafe1df")!)

let task = URLSession.shared.dataTask(with: request)  data, response, error in
    guard let data = data else  return 
    let decoder = JSONDecoder()
    decoder.keyDecodingStrategy = .convertFromSnakeCase

    do 
        let weatherQuery = try decoder.decode(WeatherQuery.self, from: data)
        ...
     catch 
        print("[DEBUG] Error is here - \(error)")
    


task.resume()

【讨论】:

谢谢,这应该有助于理解 Codable 和 Decoder【参考方案2】:

看看下面... 以下是来自开放天气 API 的所有数据。随心所欲地定制。

let task = URLSession.shared.dataTask(with: request) 
    (data, response, error) in

    //If data did return and is not nil
    if let dataReturned = data 

        //If let json
        if let json = try? JSONSerialization.jsonObject(with: dataReturned, options: .allowFragments) as? NSDictionary 

            //print("**** WEATHER JSON **** = \(json)")

            //Date Formatter
            let dateFormatter = DateFormatter()
            dateFormatter.dateFormat = "HH:mm"

            //Picking Apart JSON
            let locationName = json["name"] as? String
            let visibility = json["visibility"] as? Int
            let mainInformation = json["main"] as? NSDictionary
            let weatherInArray = json["weather"] as? NSArray
            let coords = json["coord"] as? NSDictionary
            let system = json["sys"] as? NSDictionary
            let wind = json["wind"] as? NSDictionary
            let weather = weatherInArray?[0] as? NSDictionary

            //Main Information
            let temp = mainInformation?.value(forKey: "temp") as? Double
            let humidity = mainInformation?.value(forKey: "humidity") as? Int
            let pressure = mainInformation?.value(forKey: "pressure") as? Int
            let roundedTemp = Int(round(temp ?? 0.00))

            //Weather Information
            let weatherDiscription = weather?.value(forKey: "description") as? String
            let weatherID = weather?.value(forKey: "id") as? Int

            //Coords Information
            let longitude = coords?.value(forKey: "lon") as? Double
            let latitude = coords?.value(forKey: "lat") as? Double

            //System Information
            let sunrise = system?.value(forKey: "sunrise") as? Int
            let sunriseTwo = Double(sunrise ?? 0)
            let dateSunrise = NSDate(timeIntervalSince1970: sunriseTwo)
            let sunriseTime = dateFormatter.string(from: dateSunrise as Date)

            let sunset = system?.value(forKey: "sunset") as? Int
            let sunsetTwo = Double(sunset ?? 0)
            let dateSunset = NSDate(timeIntervalSince1970: sunsetTwo)
            let sunsetTime = dateFormatter.string(from: dateSunset as Date)

            //Wind Information
            let windSpeed = wind?.value(forKey: "speed") as? Double
            let windAngle = wind?.value(forKey: "deg") as? Double

            //APPEND TO YOUR ARRAY HERE
            Your_Array_Here = Your_Array_here.append(WeatherDataClass(cityName: ***  , currentWeather: ***, weatherDescription: *** ))



        

    



task.resume()

【讨论】:

以上是关于如何使用 JSON.serializer 在 Swift 中解析 JSON的主要内容,如果未能解决你的问题,请参考以下文章

如何配置 ServiceStack Json Serializer 以将 bool 值写入 int 或 byte?

在ASP.NET MVC中全局应用JSON Serializer设置

用于深层嵌套对象的自定义Json Serializer

ServiceStack Json Serializer 忽略属性

学习转载One more ABAP to JSON Serializer and Deserializer

将 Django 对象传递给 ExtJS 的正确方法