1

我目前正在使用 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


    }

}
4

2 回答 2

1

当您遍历list数组时,每个元素应该已经在 J​​SON 文件中基于元素进行了排序dt。此外,数组中的每个元素 ( 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。

于 2016-06-22T13:59:42.910 回答
0

正如@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)")
}
于 2016-06-22T15:49:35.387 回答