Swift 3中可选项的奇怪行为

时间:2016-10-28 21:00:08

标签: json swift3 optional

使用Swift 3解析JSON数据时遇到了一种奇怪的行为。

do {
  let json = try JSONSerialization.jsonObject(with: data!, options: []) as! NSDictionary
  let items:[AnyObject] = (json["items"] as? [AnyObject])!
  for item in items {
    let id:String = item["id"] as! String
    print("ID: \(id)")
    let info = item["volumeInfo"] as AnyObject
    print(info)
    let title = info["title"]
    print(title)
  }
} catch {
  print("error thrown")
}

这会产生以下输出。请注意,info是可选的,但如果我尝试打开它,则说明它不是可选的!脚本在let title = info["title"]崩溃。因此,我无法访问标题密钥。自Swift 2以来,此行为已发生变化。

ID: lbvUD6LUyV8C
Optional({
  publishedDate = 2002;
  publisher = "Sams Publishing";
  title = "Java Deployment with JNLP and WebStart";
})

4 个答案:

答案 0 :(得分:0)

info的运行时类型为Optional<Something>,但编译时类型(显式转换时)为AnyObject。编译器如何知道AnyObject恰好是Optional<Something>,除非你告诉它(以演员表的形式)?

尝试:

let info = item["volumeInfo"] as AnyObject?

现在编译器知道它是Optional<AnyObject>,所以你可以打开它。

答案 1 :(得分:0)

您可以执行以下操作:

do {
    let json = try JSONSerialization.jsonObject(with: data!) as! [String: Any]
    let items = json["items"] as! [[String: Any]]
    for item in items {
        let id = item["id"] as! String
        let info = item["volumeInfo"] as! [String: Any]
        let title = info["title"] as! String

        print(id)
        print(info)
        print(title)
    }
} catch {
    print("error thrown: \(error)")
}

我可能会建议删除!强制展开的代码(如果JSON不是你想要的形式,你真的希望崩溃吗?),但希望这说明了基本的想法。

答案 2 :(得分:0)

在Swift 3中,编译器必须知道所有下标对象的类型(如果它是数组或字典)。 <{1}} - 已经在Swift 3中更改为AnyObject是不够的。

因为您知道键Any的值是字典,所以最好使用可选绑定

volumeInfo

答案 3 :(得分:0)

这应该做:

guard let json = try? JSONSerialization.jsonObject(with: data!, options: []) as! [String: AnyObject],
    let items = json["items"] as! Array<AnyObject>? else {
    return
}

for item in items {
    let id = item["id"] as! String
    if let info = item["volumeInfo"] as? [String: AnyObject] {
        let title = info["title"] as! String
    } else {
        // do something
    }
}