在 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 示例一样的主要内容,如果未能解决你的问题,请参考以下文章

在 Swift 3 中正确解析 JSON

在 Swift 3 中正确解析 JSON

在 Swift 3 中正确解析 JSON

如何使用 Alamofire 在 Swift 3 中解析 JSON?

使用 Alamofire 在 swift 3 中解析 Json

swift 1.2 中的 JSON 解析问题