在 Swift 中解析 json,AnyObject 类型
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/24671249/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Parse json in Swift, AnyObject type
提问by alpennec
I'm trying to parse a json but I have some difficulties with the data types and notably the AnyObject type + downcasting.
我正在尝试解析 json,但我在数据类型方面遇到了一些困难,尤其是 AnyObject 类型 + 向下转换。
Let's consider the following json (it's an extract of a full json).
让我们考虑以下 json(它是完整 json 的摘录)。
{ "weather":
[
{
"id":804,
"main":"Clouds",
"description":"overcast clouds",
"icon":"04d"
}
],
}
To me, the json can be described as follow :
对我来说,json 可以描述如下:
- 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)
My json is of type AnyObject! (I use JSONObjectWithDatato get the JSON from a URL).
我的 json 是 AnyObject 类型的!(我用来JSONObjectWithData从 URL 获取 JSON)。
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
}
}
Here is the error I got
这是我得到的错误
Playground execution failed: error: <EXPR>:28:56: error: '[AnyObject]' is not a subtype of '(String, AnyObject)'
if let weatherDictionary = dict["weather"] as? [AnyObject] {
I don't understand why dict["weather"] is compared to a subtype of (String, AnyObject) and not AnyObject.
我不明白为什么将 dict["weather"] 与 (String, AnyObject) 而不是 AnyObject 的子类型进行比较。
I declared my dictionary as [String: AnyObject], so I i access a value using the String key, I should have an AnyObject, no ?
我将我的字典声明为 [String: AnyObject],所以我使用 String 键访问一个值,我应该有一个 AnyObject,不是吗?
If I use NSDictionary instead of [String: AnyObject], it works.
如果我使用 NSDictionary 而不是 [String: AnyObject],它会起作用。
If I use NSArray instead of [AnyObject], it works.
如果我使用 NSArray 而不是 [AnyObject],它会起作用。
- 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]."
EDIT
编辑
I forgot to force unwrapping the dict["weather"]!.
我忘了强制打开 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)")
}
}
}
Note that we should double check for the existence of the first Optional.
请注意,我们应该仔细检查第一个 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")
}
}
}
回答by Daniel T.
This works fine for me in the playground and in the terminal using env xcrun swift
这对我来说在操场上和在终端中使用很好 env xcrun swift
UPDATED FOR SWIFT 4 AND CODABLE
为 Swift 4 和 Codable 更新
Here is a Swift 4 example using the Codable protocol.
这是一个使用 Codable 协议的 Swift 4 示例。
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)
}
UPDATED FOR SWIFT 3.0
为 Swift 3.0 更新
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!
我更新了 Swift 3 的代码,并展示了如何将解析的 JSON 包装到对象中。感谢大家的投票!
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)
}
-- Previous Answer --
-- 上一个答案 --
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)
}
}
}
Since I'm still getting up-votes for this answer, I figured I would revisit it for Swift 2.0:
由于我仍然为这个答案投票,我想我会为 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)
}
The biggest difference is that the variable jsonis no longer an optional type and the do/try/catch syntax. I also went ahead and typed id, main, and description.
最大的区别是变量json不再是可选类型和 do/try/catch 语法。我也继续输入id, main, 和description。
回答by dankogai
Try:
尝试:
With it you can go like this:
有了它,你可以这样:
let obj:[String:AnyObject] = [
"array": [JSON.null, false, 0, "", [], [:]],
"object":[
"null": JSON.null,
"bool": true,
"int": 42,
"double": 3.141592653589793,
"string": "a α\t弾\n",
"array": [],
"object": [:]
],
"url":"http://blog.livedoor.com/dankogai/"
]
let json = JSON(obj)
json.toString()
json["object"]["null"].asNull // NSNull()
json["object"]["bool"].asBool // true
json["object"]["int"].asInt // 42
json["object"]["double"].asDouble // 3.141592653589793
json["object"]["string"].asString // "a α\t弾\n"
json["array"][0].asNull // NSNull()
json["array"][1].asBool // false
json["array"][2].asInt // 0
json["array"][3].asString // ""
回答by isair
Using my library (https://github.com/isair/JSONHelper) you can do this with your jsonvariable of type AnyObject:
使用我的库(https://github.com/isair/JSONHelper),您可以使用AnyObject 类型的json变量执行此操作:
var weathers = [Weather]() // If deserialization fails, JSONHelper just keeps the old value in a non-optional variable. This lets you assign default values like this.
if let jsonDictionary = json as? JSONDictionary { // JSONDictionary is an alias for [String: AnyObject]
weathers <-- jsonDictionary["weather"]
}
Had your array not been under the key "weather", your code would have been just this:
如果您的数组不在关键“天气”下,您的代码将是这样的:
var weathers = [Weather]()
weathers <-- json
Or if you have a json string in your hands you can just pass it as well, instead of creating a JSON dictionary from the string first. The only setup you need to do is writing a Weather class or struct:
或者,如果您手中有一个 json 字符串,您也可以直接传递它,而不是先从字符串创建一个 JSON 字典。您需要做的唯一设置是编写 Weather 类或结构:
struct Weather: Deserializable {
var id: String?
var name: String?
var description: String?
var icon: String?
init(data: [String: AnyObject]) {
id <-- data["id"]
name <-- data["name"]
description <-- data["description"]
icon <-- data["icon"]
}
}

