Swift 3 中可选项的奇怪行为
Strange behaviour of optionals in Swift 3
我在使用 Swift 解析 JSON 数据时遇到了一个奇怪的行为 3.
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")
}
这会产生以下输出。请注意,信息是可选的,但如果我尝试打开它,它会声明它不是可选的!脚本在 let title = info["title"]
崩溃,结果我无法访问标题键。自 Swift 2.
以来,此行为已发生变化
ID: lbvUD6LUyV8C
Optional({
publishedDate = 2002;
publisher = "Sams Publishing";
title = "Java Deployment with JNLP and WebStart";
})
info
的运行时类型是 Optional<Something>
,但编译时类型(如您显式转换的那样)是 AnyObject
。除非您告诉它(以强制转换的形式),否则编译器应该如何知道 AnyObject
恰好是 Optional<Something>
?
尝试:
let info = item["volumeInfo"] as AnyObject?
现在编译器知道它是一个 Optional<AnyObject>
,所以你可以打开它。
您可以这样做:
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 不是您预期的形式,您真的希望它崩溃吗?),但希望这能说明基本思路。
在Swift 3 中,编译器必须知道所有下标对象的类型,如果它是数组或字典。 AnyObject
– 在 Swift 3 中已更改为 Any
– 不够。
因为您知道键 volumeInfo
的值是一个字典,因此最好使用可选绑定
let info = item["volumeInfo"] as? [String:Any] {
print(info)
let title = info["title"] as! String
print(title)
}
应该这样做:
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
}
}
我在使用 Swift 解析 JSON 数据时遇到了一个奇怪的行为 3.
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")
}
这会产生以下输出。请注意,信息是可选的,但如果我尝试打开它,它会声明它不是可选的!脚本在 let title = info["title"]
崩溃,结果我无法访问标题键。自 Swift 2.
ID: lbvUD6LUyV8C
Optional({
publishedDate = 2002;
publisher = "Sams Publishing";
title = "Java Deployment with JNLP and WebStart";
})
info
的运行时类型是 Optional<Something>
,但编译时类型(如您显式转换的那样)是 AnyObject
。除非您告诉它(以强制转换的形式),否则编译器应该如何知道 AnyObject
恰好是 Optional<Something>
?
尝试:
let info = item["volumeInfo"] as AnyObject?
现在编译器知道它是一个 Optional<AnyObject>
,所以你可以打开它。
您可以这样做:
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 不是您预期的形式,您真的希望它崩溃吗?),但希望这能说明基本思路。
在Swift 3 中,编译器必须知道所有下标对象的类型,如果它是数组或字典。 AnyObject
– 在 Swift 3 中已更改为 Any
– 不够。
因为您知道键 volumeInfo
的值是一个字典,因此最好使用可选绑定
let info = item["volumeInfo"] as? [String:Any] {
print(info)
let title = info["title"] as! String
print(title)
}
应该这样做:
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
}
}