在 Swift 3 中解析 JSON,就像 Apple 的 Swift 2 示例一样
Posted
技术标签:
【中文标题】在 Swift 3 中解析 JSON,就像 Apple 的 Swift 2 示例一样【英文标题】:Parsing JSON in Swift 3 like Apple's example for Swift 2 【发布时间】:2017-01-12 05:53:01 【问题描述】:我正在解析来自 Instagram API 的 JSON 响应。顶层对象包含一些元数据,我感兴趣的条目包含在一个名为“data”的数组对象中。
Apple 的帖子here,使用 Swift 2,并在 Swift 3 发布的前一天发布(我相信)。这篇文章非常有帮助,并且具有与我试图用来获取我感兴趣的项目的字典相同的模式。 JSON 的结构非常相似。
代码如下:
let session = URLSession.shared
let task = session.dataTask(with: mediaURL(), completionHandler: (data, response, error) in
if let data = data,
let json = try? JSONSerialization.jsonObject(with: data, options: []) as? [String: Any]
for case let items in json["data"]
// parse each item
编译器抛出错误“Type '[String: Any]?'没有下标成员”,在for case let items in json["data"]
行上。 if let
链中的变量json
的类型为[String: Any]?
。我怎样才能避免这种情况,并构造绑定,以便我在 json
变量中获得一个键入 [String: Any]
的字典?
请注意,我不是在问如何解析 JSON。我明白那个。 Apple 的帖子正是我想使用的模式,我想了解如何将这篇帖子中的代码更新为 Swift 3。
更新:
感谢下面 cmets 的输入,我仔细查看了我正在使用的类型。因为我的 JSON 有很多字典数组的字典数组,所以我用这段代码来解析它:
let json = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any],
let items = json["data"] as? [[String: Any]]
for item in items
if let mediaType = item["type"] as? String,
let mediaID = item["id"] as? String,
let images = item["images"] as? [String: Any],
let standardImg = images["standard_resolution"] as? [String: Any],
let standardImgURL = standardImg["url"] as? String
// Create instances with JSON data…
我可以使用一个框架,但这帮助我了解了更多关于解析返回的高度嵌套的 JSON 的知识,而不仅仅是简单的平面值。
【问题讨论】:
你必须告诉编译器json["data"]
中值的预期类型是什么。
由于try?
,您变得可选,所以这样写let json = (try? JSONSerialization.jsonObject(with: data, options: [])) as? [String: Any]
还需要指定json["data"]
的类型
感谢您的回复。我不明白为什么编译器可以推断出 Swift 2 的类型(Apple 的示例在该帖子中不包括 json["data"]
的类型,并且类型被正确推断。也许我的 JSON 没有我想象的那么接近。跨度>
@aaronfalls 我认为类型推断与 JSON 没有任何关系。记住:Swift 是静态类型的! a) 类型推断发生在编译时;那时没有 JSON 存在。 b) 无论如何,JSON 只有字符串。
【参考方案1】:
您可以通过明确指定所需的 json
类型来获得更多有用的错误消息,而不是费力地进行任何类型推断:
let json: [String: Any] = try? JSONSerialization.jsonObject(...) as? [String: Any]
for case let items in json["data"]
// parse each item
现在错误(try?
)是:
错误:可选类型
'[String : Any]??'
的值未解包; 您的意思是使用'try!'
还是与'?'
链接?
这为您提供了有关如何进行的非常清晰的说明。基本上,您并没有打开可选项的包装,而是在它周围添加了另一层!使用 try!
+ as?
、try?
+ as!
或 try
+ as
(后者要求您处理如果转换失败时抛出的错误)可以得到您想要的。
请注意,您将无法迭代 json["data"]
,因为 Any
¹ 不可迭代。您必须使访问的数据具有有用的类型,例如:
switch json["data"]
case let items as Array<String>:
for item in items
// parse
default: throw "can't parse these data"
我建议你使用 Any
以外的其他东西;也许为此目的创建一个协议JsonData
并将其扩展到您预期的所有内容中。
for
后面的那个多余的case
甚至让它输入Any?
!
【讨论】:
感谢您的回复,类型信息很有帮助。将类型注释添加到let json
会有所帮助。你提到的switch示例,我没有得到结果,可能是JSON的结构。我想我需要弄清楚如何解析 JSON 的 data
元素(从返回的 Data
实例在将其转换为对象之前,然后我可以使用 jsonObject
转换每个元素。这就是我真正想要的尝试这样做,但在顶层转换它会使我真正感兴趣的数组变平。
@aaronfalls 我很高兴能帮上忙!我认为很明显,我无法帮助您处理您所拥有的特定 JSON。您可能想查看 SwiftyJSON 或其他为丑陋的标准库提供更好包装的库。以上是关于在 Swift 3 中解析 JSON,就像 Apple 的 Swift 2 示例一样的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 Alamofire 在 Swift 3 中解析 JSON?