首先, 永远不要从远程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是一种排列合理的文本格式。读取JSON字符串非常容易。 仔细阅读字符串 。只有六种不同的类型–两种收集类型和四种值类型。
收集类型为
- 数组 -JSON:方括号中的对象
[]
-Swift:[Any]
但在大多数情况下[[String:Any]]
- 字典 -JSON:大括号中的对象
{}-Swift:[String:Any]
值类型为
- 字符串 -JSON:双引号中的任何值
"Foo"
,偶数"123"
或"false"
– Swift:String
- 数字 -JSON:数值 不带 双引号
123
或123.0
– Swift:Int
或Double
- 布尔 -JSON:
true
或false
不 使用双引号-Swift:true
或false
- null -JSON:
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
================================================== =========================
在Swift 4+中,该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
。 - snaked_cased JSON键可被转化为 驼峰 与
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 deprer = JSonDeprer() deprer.dateDecodingStrategy = .secondsSince1970 deprer.keyDecodingStrategy = .convertFromSnakeCase let result = try deprer.depre(Weather.self, from: data) print(result)} catch { print(error)}其他可编码来源:
- 苹果:对自定义类型进行编码和解码
- HackingWithSwift:可编码备忘单
- Ray Wenderlich:Swift中的编码和解码



