我正在尝试获取JSON响应并将结果存储在变量中。在以前的Swift版本中,我已经使用过此代码的版本,直到Xcode
8的GM版本发布为止。我在StackOverflow上看到了一些类似的文章:Swift 2解析JSON-
无法
在Swift
3中下标’AnyObject’类型的值和JSON解析。
但是,似乎此处传达的想法不适用于这种情况。
如何在Swift 3中正确解析JSON响应?在Swift 3中读取JSON的方式是否有所改变?
下面是有问题的代码(可以在操场上运行):
import Cocoa
let url = "https://api.forecast.io/forecast/apiKey/37.5673776,122.048951"
if let url = NSURL(string: url) {
if let data = try? Data(contentsOf: url as URL) {
do {
let parsedData = try JSONSerialization.jsonObject(with: data as Data, options: .allowFragments)
//Store response in NSDictionary for easy access
let dict = parsedData as? NSDictionary
let currentConditions = "\(dict!["currently"]!)"
//This produces an error, Type 'Any' has no subscript members
let currentTemperatureF = ("\(dict!["currently"]!["temperature"]!!)" as NSString).doubleValue
//Display all current conditions from API
print(currentConditions)
//Output the current temperature in Fahrenheit
print(currentTemperatureF)
}
//else throw an error detailing what went wrong
catch let error as NSError {
print("Details of JSON parsing error:\n \(error)")
}
}
}
编辑: 这是API调用之后的结果示例print(currentConditions)
["icon": partly-cloudy-night, "precipProbability": 0, "pressure": 1015.39, "humidity": 0.75, "precipIntensity": 0, "windSpeed": 6.04, "summary": Partly Cloudy, "ozone": 321.13, "temperature": 49.45, "dewPoint": 41.75, "apparentTemperature": 47, "windBearing": 332, "cloudCover": 0.28, "time": 1480846460]
首先, 永远不要从远程URL同步加载数据 ,而应始终使用异步方法,例如URLSession
。
‘Any’没有下标成员
是因为编译器没有什么类型的中间对象(例如理念currently
的["currently"]!["temperature"]
),并且由于使用的是基金会收藏类型,如NSDictionary
编译器在所有有关的类型不知道。
另外,在Swift 3中,需要通知编译器 所有 下标对象的类型。
您必须将JSON序列化的结果转换为实际类型。
此代码的用途URLSession
和 专门 斯威夫特本地类型
let urlString = "https://api.forecast.io/forecast/apiKey/37.5673776,122.048951"
let url = URL(string: urlString)
URLSession.shared.dataTask(with:url!) { (data, response, error) in
if error != nil {
print(error)
} else {
do {
let parsedData = try JSONSerialization.jsonObject(with: data!) as! [String:Any]
let currentConditions = parsedData["currently"] as! [String:Any]
print(currentConditions)
let currentTemperatureF = currentConditions["temperature"] as! Double
print(currentTemperatureF)
} catch let error as NSError {
print(error)
}
}
}.resume()
要打印所有currentConditions
可以写的键/值对
let currentConditions = parsedData["currently"] as! [String:Any]
for (key, value) in currentConditions {
print("\(key) - \(value) ")
}
关于jsonObject(with data
以下内容的注释:
许多(看来都是)教程建议.mutableContainers
或.mutableLeaves
选项在Swift中完全是胡说八道。这两个选项是遗留的Objective-
C选项,用于将结果分配给NSMutable...
对象。在Swift中var
,默认情况下任何变量都是可变的,并且传递这些选项中的任何一个并将结果分配给let
常量都完全无效。此外,大多数实现绝不会改变反序列化的JSON。
唯一的(罕见)选项,在夫特是有用是.allowFragments
如果如果JSON根对象可以是一个值类型是必需(String
,Number
,Bool
或null
)而不是集合类型中的一个(array
或dictionary
)。但通常会省略options
表示
No options 的参数。
================================================== =========================
JSON是一种排列合理的文本格式。读取JSON字符串非常容易。 仔细阅读字符串 。只有六种不同的类型–两种收集类型和四种值类型。
收集类型为
[]
-Swift:[Any]
但在大多数情况下[[String:Any]]
{}
-Swift:[String:Any]
值类型为
"Foo"
,偶数"123"
或"false"
– Swift:String
123
或123.0
– Swift:Int
或Double
true
或false
不 使用双引号-Swift:true
或false
null
– Swift:NSNull
根据JSON规范,字典中的所有键都必须为String
。
基本上,始终建议使用可选绑定安全地解开可选选项
如果根对象是字典({}
),则将类型强制转换为[String:Any]
if let parsedData = try JSONSerialization.jsonObject(with: data!) as? [String:Any] { ...
并使用(OneOfSupportedJSONTypes
是JSON集合或如上所述的值类型)通过键检索值。
if let foo = parsedData["foo"] as? OneOfSupportedJSONTypes {
print(foo)
}
如果根对象是数组([]
),则将类型强制转换为[[String:Any]]
if let parsedData = try JSONSerialization.jsonObject(with: data!) as? [[String:Any]] { ...
并通过遍历数组
for item in parsedData {
print(item)
}
如果您需要特定索引处的项目,还检查索引是否存在
if let parsedData = try JSONSerialization.jsonObject(with: data!) as? [[String:Any]], parsedData.count > 2,
let item = parsedData[2] as? OneOfSupportedJSONTypes {
print(item)
}
}
在极少数情况下,JSON只是值类型之一(而不是集合类型),您必须传递.allowFragments
选项并将结果转换为适当的值类型,例如
if let parsedData = try JSONSerialization.jsonObject(with: data!, options: .allowFragments) as? String { ...
苹果在Swift博客中发表了一篇详尽的文章:在Swift中使用JSON
================================================== =========================
Codable
协议提供了一种将JSON直接解析为结构/类的更便捷的方法。例如,问题中的给定JSON示例(稍作修改)
let jsonString = """
{"icon": "partly-cloudy-night", "precipProbability": 0, "pressure": 1015.39, "humidity": 0.75, "precip_intensity": 0, "wind_speed": 6.04, "summary": "Partly Cloudy", "ozone": 321.13, "temperature": 49.45, "dew_point": 41.75, "apparent_temperature": 47, "wind_bearing": 332, "cloud_cover": 0.28, "time": 1480846460}
"""
可以解码为struct Weather
。Swift类型与上述相同。还有一些其他选项:
URL
可以直接解码为URL
。time
整数可以被解码为Date
与所述dateDecodingStrategy
.secondsSince1970
。keyDecodingStrategy
.convertFromSnakeCase
struct Weather: Decodable {
let icon, summary: String
let pressure: Double, humidity, windSpeed : Double
let ozone, temperature, dewPoint, cloudCover: Double
let precipProbability, precipIntensity, apparentTemperature, windBearing : Int
let time: Date
}
let data = Data(jsonString.utf8)
do {
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .secondsSince1970
decoder.keyDecodingStrategy = .convertFromSnakeCase
let result = try decoder.decode(Weather.self, from: data)
print(result)
} catch {
print(error)
}
其他可编码来源:
我试图获取一个JSON响应,并将结果存储在一个变量中。我在以前的Swift版本中使用过这个代码版本,直到Xcode8的GM版本发布。我在StackOverflow上看了几篇类似的文章:Swift 2 Parsing JSON-Cant下标类型为“anyObject”的值和Swift 3中的JSON Parsing。 然而,这里所传达的思想似乎不适用于这种情况。 如何正确解析Swift3中的JSON
问题内容: 我是Python的新手。我想解析一个csv文件,以便它可以识别带引号的值-例如 1997年,福特E350,“超级豪华卡车” 应该拆分为 (“ 1997”,“福特”,“ E350”,“超级豪华卡车”) 并不是 (“ 1997”,“福特”,“ E350”,“超级”,“豪华卡车””) 以上就是我使用类似的东西所得到的。 我该怎么做呢?同样最好将这些值存储在数组或其他数据结构中吗?因为在我从c
代码: 这很奇怪,因为BeansException继承了Throwable:http://static.springsource.org/spring/docs/2.0.2/api/org/springframework/beans/BeansException.html。原因是什么,如何修复?
问题内容: 我有一个非常棘手的问题,我希望有人能对此有所启发。我正在使用Jquery从另一个网站(我拥有)检索Http响应。收到DOM后,我将对其进行解析以获取某些信息。但是,当我尝试获取链接的href属性时,IE会将本地域添加到href的开头! 这是我的代码: 我的变量PageLink应该是“ /pages/getThisPage.aspx?id=8347”。但是,它将作为“ http://my
我有一个自由标记 ftl 模板文件,该文件包含在 IntelliJ 项目中的标签库中。问题是 JspTaglibs 在 IntelliJ 中没有解决。该错误突出显示文本 ,错误消息为“无法解析变量'JspTaglibs'”。文件内容如下: 这是一个导入的Maven项目。包含的ftl位于一个已编译的JAR文件中,我将它作为内容根包含在一个Web模块中。 关于解析“JspTaglibs”以便可以为自由
在Rails中,我查询数据库以构建highcharts的数据对象。 这是我的控制器中的方法: 终止 现在,在我看来,我正试图在一个脚本中把它拉出来。 ---脚本--- ---脚本--- 当我打印到控制台时,我可以看到对象及其所有数据。此外,当我打印到html时,输出看起来是正确的: "[{\"名称\":\"原 但是当我去打印数据变量时,它是null(显然是由于不是有效输入)。我搞砸了什么?