在Swift中解析JSON,AnyObject类型 [英] Parse json in Swift, AnyObject type
问题描述
我正在尝试解析json,但是我在数据类型上遇到了一些困难,尤其是AnyObject类型+向下转换.
I'm trying to parse a json but I have some difficulties with the data types and notably the AnyObject type + downcasting.
让我们考虑以下json(它是完整json的一部分).
Let's consider the following json (it's an extract of a full json).
{ "weather":
[
{
"id":804,
"main":"Clouds",
"description":"overcast clouds",
"icon":"04d"
}
],
}
对我来说,json可以描述如下:
To me, the json can be described as follow :
- json: Dictionary of type [String: AnyObject] (or NSDictionary, so = [NSObject, AnyObject] in Xcode 6 b3)
- "weather": Array of type [AnyObject] (or NSArray)
- Dictionary of type [String: AnyObject] (or NSDictionary, so = [NSObject, AnyObject] in Xcode 6 b3)
我的json是AnyObject类型! (我使用JSONObjectWithData
从URL获取JSON).
My json is of type AnyObject! (I use JSONObjectWithData
to get the JSON from a URL).
然后我想访问天气词典.这是我写的代码.
I then want to access the weather Dictionary. Here is the code I wrote.
var localError: NSError?
var json: AnyObject! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: &localError)
if let dict = json as? [String: AnyObject] {
if let weatherDictionary = dict["weather"] as? [AnyObject] {
// Do stuff with the weatherDictionary
}
}
这是我遇到的错误
Playground execution failed: error: <EXPR>:28:56: error: '[AnyObject]' is not a subtype of '(String, AnyObject)'
if let weatherDictionary = dict["weather"] as? [AnyObject] {
我不明白为什么将dict ["weather"]与(String,AnyObject)而不是AnyObject的子类型进行比较.
I don't understand why dict["weather"] is compared to a subtype of (String, AnyObject) and not AnyObject.
我将字典声明为[String:AnyObject],所以我使用String键访问一个值,我应该有一个AnyObject,不是吗?
I declared my dictionary as [String: AnyObject], so I i access a value using the String key, I should have an AnyObject, no ?
如果我使用NSDictionary而不是[String:AnyObject],它将起作用.
If I use NSDictionary instead of [String: AnyObject], it works.
如果我使用NSArray而不是[AnyObject],那么它将起作用.
If I use NSArray instead of [AnyObject], it works.
- The Xcode 6 beta 3 release notes tell that "NSDictionary* is now imported from Objective-C APIs as [NSObject : AnyObject].".
- And the Swift book: "When you bridge from an NSArray object to a Swift array, the resulting array is of type [AnyObject]."
编辑
我忘了强迫解开字典["weather"]!.
I forgot to force unwrapping the dict["weather"]!.
if let dict = json as? [String: AnyObject] {
println(dict)
if let weatherDictionary = dict["weather"]! as? [AnyObject] {
println("\nWeather dictionary:\n\n\(weatherDictionary)")
if let descriptionString = weatherDictionary[0]["description"]! as? String {
println("\nDescription of the weather is: \(descriptionString)")
}
}
}
请注意,我们应该仔细检查第一个Optional的存在.
Note that we should double check for the existence of the first Optional.
if let dict = json as? [String: AnyObject] {
for key in ["weather", "traffic"] {
if let dictValue = dict[key] {
if let subArray = dictValue as? [AnyObject] {
println(subArray[0])
}
} else {
println("Key '\(key)' not found")
}
}
}
推荐答案
这对我来说在操场上和使用env xcrun swift
This works fine for me in the playground and in the terminal using env xcrun swift
已更新为SWIFT 4和可编码
UPDATED FOR SWIFT 4 AND CODABLE
这是一个使用Codable协议的Swift 4示例.
Here is a Swift 4 example using the Codable protocol.
var jsonStr = "{\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}],}"
struct Weather: Codable {
let id: Int
let main: String
let description: String
let icon: String
}
struct Result: Codable {
let weather: [Weather]
}
do {
let weather = try JSONDecoder().decode(Result.self, from: jsonStr.data(using: .utf8)!)
print(weather)
}
catch {
print(error)
}
已为SWIFT 3.0更新
UPDATED FOR SWIFT 3.0
我已经更新了Swift 3的代码,还展示了如何将已解析的JSON包装到对象中.感谢所有的投票!
I have updated the code for Swift 3 and also showed how to wrap the parsed JSON into objects. Thanks for all the up votes!
import Foundation
struct Weather {
let id: Int
let main: String
let description: String
let icon: String
}
extension Weather {
init?(json: [String: Any]) {
guard
let id = json["id"] as? Int,
let main = json["main"] as? String,
let description = json["description"] as? String,
let icon = json["icon"] as? String
else { return nil }
self.id = id
self.main = main
self.description = description
self.icon = icon
}
}
var jsonStr = "{\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}],}"
enum JSONParseError: Error {
case notADictionary
case missingWeatherObjects
}
var data = jsonStr.data(using: String.Encoding.ascii, allowLossyConversion: false)
do {
var json = try JSONSerialization.jsonObject(with: data!, options: [])
guard let dict = json as? [String: Any] else { throw JSONParseError.notADictionary }
guard let weatherJSON = dict["weather"] as? [[String: Any]] else { throw JSONParseError.missingWeatherObjects }
let weather = weatherJSON.flatMap(Weather.init)
print(weather)
}
catch {
print(error)
}
-上一个答案-
import Foundation
var jsonStr = "{\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}],}"
var data = jsonStr.dataUsingEncoding(NSASCIIStringEncoding, allowLossyConversion: false)
var localError: NSError?
var json: AnyObject! = NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers, error: &localError)
if let dict = json as? [String: AnyObject] {
if let weather = dict["weather"] as? [AnyObject] {
for dict2 in weather {
let id = dict2["id"]
let main = dict2["main"]
let description = dict2["description"]
println(id)
println(main)
println(description)
}
}
}
由于我仍在为这个答案投票,我想我会在Swift 2.0上重新访问它:
Since I'm still getting up-votes for this answer, I figured I would revisit it for Swift 2.0:
import Foundation
var jsonStr = "{\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}],}"
var data = jsonStr.dataUsingEncoding(NSASCIIStringEncoding, allowLossyConversion: false)
do {
var json = try NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers)
if let dict = json as? [String: AnyObject] {
if let weather = dict["weather"] as? [AnyObject] {
for dict2 in weather {
let id = dict2["id"] as? Int
let main = dict2["main"] as? String
let description = dict2["description"] as? String
print(id)
print(main)
print(description)
}
}
}
}
catch {
print(error)
}
最大的区别是变量json
不再是可选类型,并且不再是do/try/catch语法.我还继续输入了id
,main
和description
.
The biggest difference is that the variable json
is no longer an optional type and the do/try/catch syntax. I also went ahead and typed id
, main
, and description
.
这篇关于在Swift中解析JSON,AnyObject类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!