【问题标题】:How to extract JSON data from array inside of array in Swift 2.0如何在 Swift 2.0 中从数组内部的数组中提取 JSON 数据
【发布时间】:2016-10-24 12:01:15
【问题描述】:

我目前正在使用 Openweathermap.org 获取天气预报信息。这是我从他们的 API 获得的 JSON 对象:

{  
   "city":{  },
   "cod":"200",
   "message":0.0029,
   "cnt":40,
   "list":[  
      {  
         "dt":1466532000,
         "main":{  
            "temp":296.52,
            "temp_min":294.864,
            "temp_max":296.52,
            "pressure":1004.95,
            "sea_level":1023.45,
            "grnd_level":1004.95,
            "humidity":58,
            "temp_kf":1.65
         },
         "weather":[  
            {  
               "id":803,
               "main":"Clouds",
               "description":"broken clouds",
               "icon":"04d"
            }
         ],
         "clouds":{  },
         "wind":{  },
         "sys":{  },
         "dt_txt":"2016-06-21 18:00:00"
      },
      {  
         "dt":1466542800,
         "main":{  },
         "weather":[  ],
         "clouds":{  },
         "wind":{  },
         "sys":{  },
         "dt_txt":"2016-06-21 21:00:00"
      },
      {  
         "dt":1466553600,
         "main":{  },
         "weather":[  ],
         "clouds":{  },
         "wind":{  },
         "sys":{  },
         "dt_txt":"2016-06-22 00:00:00"
      }]
}

正如您从这个示例中看到的,在列表下有很多对象,我想要的只是温度、天气主要和描述。我创建了一个 Struct 来排序和保存所有 JSON 对象,但它一直给我错误。如何根据“dt”对其进行排序,以及如何从 JSON 中提取数据。谢谢。

这是我的结构:

import Foundation

struct FutureWeather {

 //future stuff
 var futureDt: NSDate //
 var futureMainWeather: String//
 var futureDescription: String//
 private var futureTemp: Double//
 var futureTempCelsius: Double {
    get {
        return futureTemp - 273.15
    }
 }
 var futureTempFahrenheit: Double {
    get {
        return (futureTemp - 273.15) * 1.8 + 32
    }
 }


init(futureWeatherData : [String:AnyObject]) {

    //first set of data
    let futureWeatherDictUno = futureWeatherData["list"]![0] as! [String: AnyObject]
    print(futureWeatherDictUno)

    let events = futureWeatherDictUno.sort({$0["dt"] <  $1["dt"]})

    futureDt = NSDate(timeIntervalSince1970: futureWeatherDictUno["dt"] as! NSTimeInterval)

    let mainDictOne = futureWeatherDictUno["main"] as! [String: AnyObject]
    futureTemp = mainDictOne["temp"] as! Double

    let weatherDictOne = futureWeatherDictUno["weather"]![0] as! [String: AnyObject]
    futureMainWeather = weatherDictOne["main"] as! String
    futureDescription = weatherDictOne["description"] as! String


    //the second set of data
    let futureWeatherDictDos = futureWeatherData["list"]![1] as! [String: AnyObject]
    futureDt = NSDate(timeIntervalSince1970: futureWeatherDictUno["dt"] as! NSTimeInterval)

    let mainDictTwo = futureWeatherDictDos["main"] as! [String: AnyObject]
    futureTemp = mainDictTwo["temp"] as! Double

    let weatherDictTwo = futureWeatherDictDos["weather"]![0] as! [String: AnyObject]
    futureMainWeather = weatherDictTwo["main"] as! String
    futureDescription = weatherDictTwo["description"] as! String


    }

}

【问题讨论】:

  • 嗯...什么错误?

标签: ios json swift openweathermap


【解决方案1】:

当您遍历list 数组时,每个元素都应该已经根据元素dt 在JSON 文件中进行了排序。此外,数组中的每个元素 (futureWeatherData["list"]![0]) 将只有一个 dt 键/值,因此您无法对其进行排序。

你应该做的是(这只是伪代码)如下

let futureWeather = [Weather]() 
for element : JSON in array {
   let weather = Weather(json: element) //create weather element from json
   futureWeather.append(weather)
}

您不想做的是在 FutureWeather 类的 init 方法中手动遍历列表中的每个元素。

我还建议研究使用 https://github.com/SwiftyJSON/SwiftyJSON 并在枚举中创建键以通过 json。

【讨论】:

    【解决方案2】:

    正如@Asdrubal 在他们的回答中指出的那样,SwiftyJSON 是一个有用的库。如果您想要纯基础解决方案,您可以使用NSJSONSerialization 从您的 API 数据中获取响应。我将在未来的个人服务器端 Swift 项目之前在此处发布此答案以检索天气数据:)

    import Foundation
    
    enum WeatherError: Int, ErrorType {
        /// The API response text could not be converted to an
        /// NSData object using NSUnicodeStringEncoding
        case UnexpectedAPITextEncoding = 1
    
        /// The API reponse object did not contain an array of
        /// Dictionary<String, AnyObject> objects at the "list"
        /// key
        case UnexpectedAPIResponseFormat = 2
    }
    
    /// An abstraction of a response to the OpenWeatherMap.org forecast API.
    /// Contains only date, description and temperature data, plus convenience
    /// properties to display temp in F or C.
    ///
    /// NOTE: Each of the properties on the value are Optional, reflecting the
    /// fact that the API response is sparsely populated for many of its values.
    struct OpenWeatherMapResponse {
    
        /// The date of the forecast. Could be in the future
        let futureDt: NSDate?
    
        /// Textual description of the weather conditions for the forecast time
        let futureDescription: String?
    
        /// Temp provided in K
        private let futureTemp: Double?
    
        /// Temperature for the forecast time, in degrees C
        var futureTempCelsius: Double? {
            get {
                guard let futureTemp = futureTemp else {
                    return nil
                }
                return futureTemp - 273.15
            }
        }
    
        /// Temperature for the forecast time, in degrees F
        var futureTempFahrenheit: Double? {
            get {
                guard let futureTemp = futureTemp else {
                    return nil
                }
                return (futureTemp - 273.15) * 1.8 + 32
            }
        }
    
        /// Given a member of `list` from the API response,
        /// creates an OpenWeatherMapResponse
        init(jsonObject: AnyObject) {
            if let timestamp = jsonObject["dt"] as? NSTimeInterval {
                futureDt = NSDate(timeIntervalSince1970: timestamp)
            } else {
                futureDt = nil
            }
    
            if let mainBlock = jsonObject["main"] as? [String: AnyObject],
                temp = mainBlock["temp"] as? Double {
                futureTemp = temp
            } else {
                futureTemp = nil
            }
    
            if let weatherList = jsonObject["weather"] as? [AnyObject],
                description = weatherList.first?["description"] as? String {
                futureDescription = description
            } else {
                futureDescription = nil
            }
        }
    
        /// Given a JSON Object converted from an API response, parse the object
        /// into a collection of FutureWeather values.
        /// - throws: WeatherError if the API response text is in an unexpected character encoding or in
        /// an unexpected format
        /// - returns: an array of OpenWeatherMapResponse values
        static func responsesByConvertingAPIResponseString(apiResponseString: String) throws -> [OpenWeatherMapResponse] {
    
            // NSJSONSerialization only works on NSData. Convert it before using
            guard let apiData = apiResponseString.dataUsingEncoding(NSUnicodeStringEncoding) else {
                throw WeatherError.UnexpectedAPITextEncoding
            }
    
            // Convert API response data to a Foundation AnyObject
            let jsonObject = try NSJSONSerialization.JSONObjectWithData(apiData, options: [])
    
            var weatherList = [OpenWeatherMapResponse]()
    
            guard let events = jsonObject["list"] as? [[String: AnyObject]] else {
                throw WeatherError.UnexpectedAPIResponseFormat
            }
    
            for event in events {
                weatherList.append(OpenWeatherMapResponse(jsonObject: event))
            }
    
            return weatherList
        }
    
    }
    
    
    // API response
    let jsonString = "{  \"city\":{  }, \"cod\":\"200\", \"message\":0.0029, \"cnt\":40, \"list\":[  {  \"dt\":1466532000, \"main\":{  \"temp\":296.52, \"temp_min\":294.864, \"temp_max\":296.52, \"pressure\":1004.95, \"sea_level\":1023.45, \"grnd_level\":1004.95, \"humidity\":58, \"temp_kf\":1.65 }, \"weather\":[  {  \"id\":803, \"main\":\"Clouds\", \"description\":\"broken clouds\", \"icon\":\"04d\" } ], \"clouds\":{  }, \"wind\":{  }, \"sys\":{  }, \"dt_txt\":\"2016-06-21 18:00:00\" }, {  \"dt\":1466542800, \"main\":{  }, \"weather\":[  ], \"clouds\":{  }, \"wind\":{  }, \"sys\":{  }, \"dt_txt\":\"2016-06-21 21:00:00\" }, {  \"dt\":1466553600, \"main\":{  }, \"weather\":[  ], \"clouds\":{  }, \"wind\":{  }, \"sys\":{  }, \"dt_txt\":\"2016-06-22 00:00:00\" }] }"
    
    let weatherEvents = try OpenWeatherMapResponse.responsesByConvertingAPIResponseString(jsonString)
    
    let sortedWeatherEvents = weatherEvents.sort() { a, b in a.futureDt?.timeIntervalSince1970 < b.futureDt?.timeIntervalSince1970 }
    
    // prints:
    // event: OpenWeatherMapResponse(futureDt: Optional(2016-06-21 18:00:00 +0000), futureDescription: Optional("broken clouds"), futureTemp: Optional(296.51999999999998))
    // event: OpenWeatherMapResponse(futureDt: Optional(2016-06-21 21:00:00 +0000), futureDescription: nil, futureTemp: nil)
    // event: OpenWeatherMapResponse(futureDt: Optional(2016-06-22 00:00:00 +0000), futureDescription: nil, futureTemp: nil)
    for event in sortedWeatherEvents {
        print("event: \(event)")
    }
    

    【讨论】:

      猜你喜欢
      • 2018-06-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-11-04
      • 1970-01-01
      • 2016-01-08
      • 2014-07-05
      • 2023-03-08
      相关资源
      最近更新 更多