Swift、NSJSONSerialization 和 NSError
Swift, NSJSONSerialization and NSError
问题是当数据不完整时 NSJSONSerialization.JSONObjectWithData
使应用程序崩溃并给出 unexpectedly found nil while unwrapping an Optional value
错误而不是使用 NSError 变量通知我们。所以我们无法防止崩溃。
您可以在下面找到我们正在使用的代码
var error:NSError? = nil
let dataToUse = NSJSONSerialization.JSONObjectWithData(receivedData, options: NSJSONReadingOptions.AllowFragments, error:&error) as NSDictionary
if error != nil { println( "There was an error in NSJSONSerialization") }
到目前为止我们还找不到解决方法。
问题是您将 JSON 反序列化的结果投射到 之前
检查错误。如果 JSON 数据无效(例如不完整)则
NSJSONSerialization.JSONObjectWithData(...)
returns nil
和
NSJSONSerialization.JSONObjectWithData(...) as NSDictionary
会崩溃。
这是一个正确检查错误条件的版本:
var error:NSError? = nil
if let jsonObject: AnyObject = NSJSONSerialization.JSONObjectWithData(receivedData, options: nil, error:&error) {
if let dict = jsonObject as? NSDictionary {
println(dict)
} else {
println("not a dictionary")
}
} else {
println("Could not parse JSON: \(error!)")
}
备注:
- 检查错误的正确方法是测试 return 值 ,而不是测试
错误变量。
JSON 阅读选项 .AllowFragments
在这里没有帮助。设置这个选项
只允许不是 NSArray
或 NSDictionary
实例的顶级对象,例如
{ "someString" }
您也可以在一行中完成,使用 可选类型转换 as?
:
if let dict = NSJSONSerialization.JSONObjectWithData(receivedData, options: nil, error:nil) as? NSDictionary {
println(dict)
} else {
println("Could not read JSON dictionary")
}
缺点是在else
情况下无法区分是否阅读
JSON 数据失败或者 JSON 不代表字典。
有关 Swift 3 的更新,请参阅 。
更新 Swift 3
let jsonData = Data()
do {
let jsonObject = try JSONSerialization.jsonObject(with: jsonData, options:JSONSerialization.ReadingOptions(rawValue: 0))
guard let dictionary = jsonObject as? Dictionary<String, Any> else {
print("Not a Dictionary")
// put in function
return
}
print("JSON Dictionary! \(dictionary)")
}
catch let error as NSError {
print("Found an error - \(error)")
}
Swift 2
let JSONData = NSData()
do {
let JSON = try NSJSONSerialization.JSONObjectWithData(JSONData, options:NSJSONReadingOptions(rawValue: 0))
guard let JSONDictionary: NSDictionary = JSON as? NSDictionary else {
print("Not a Dictionary")
// put in function
return
}
print("JSONDictionary! \(JSONDictionary)")
}
catch let JSONError as NSError {
print("\(JSONError)")
}
这是一个 Swift 2 扩展,您可以使用它来反序列化一个 NSDictionary:
extension NSJSONSerialization{
public class func dictionaryWithData(data: NSData, options opt: NSJSONReadingOptions) throws -> NSDictionary{
guard let d: NSDictionary = try self.JSONObjectWithData(data, options:opt) as? NSDictionary else{
throw NSError(domain: NSURLErrorDomain, code: NSURLErrorCannotParseResponse, userInfo: [NSLocalizedDescriptionKey : "not a dictionary"])
}
return d;
}
}
抱歉,我不确定如何进行保护 return 以避免创建临时文件 'd'。
Swift 3 NSJSONSerialization 示例(从文件中读取 json):
file data.json (example from here: http://json.org/example.html)
{
"glossary":{
"title":"example glossary",
"GlossDiv":{
"title":"S",
"GlossList":{
"GlossEntry":{
"ID":"SGML",
"SortAs":"SGML",
"GlossTerm":"Standard Generalized Markup Language",
"Acronym":"SGML",
"Abbrev":"ISO 8879:1986",
"GlossDef":{
"para":"A meta-markup language, used to create markup languages such as DocBook.",
"GlossSeeAlso":[
"GML",
"XML"
]
},
"GlossSee":"markup"
}
}
}
}
}
file JSONSerialization.swift
extension JSONSerialization {
enum Errors: Error {
case NotDictionary
case NotJSONFormat
}
public class func dictionary(data: Data, options opt: JSONSerialization.ReadingOptions) throws -> NSDictionary {
do {
let JSON = try JSONSerialization.jsonObject(with: data , options:opt)
if let JSONDictionary = JSON as? NSDictionary {
return JSONDictionary
}
throw Errors.NotDictionary
}
catch {
throw Errors.NotJSONFormat
}
}
}
用法
func readJsonFromFile() {
if let path = Bundle.main.path(forResource: "data", ofType: "json") {
if let data = NSData(contentsOfFile: path) as? Data {
do {
let dict = try JSONSerialization.dictionary(data: data, options: .allowFragments)
print(dict)
} catch let error {
print("\(error)")
}
}
}
}
结果(日志截图)
Swift 3:
let jsonData = Data()
do {
guard let parsedResult = try JSONSerialization.jsonObject(with: jsonData, options: .allowFragments) as? NSDictionary else {
return
}
print("Parsed Result: \(parsedResult)")
} catch {
print("Error: \(error.localizedDescription)")
}
问题是当数据不完整时 NSJSONSerialization.JSONObjectWithData
使应用程序崩溃并给出 unexpectedly found nil while unwrapping an Optional value
错误而不是使用 NSError 变量通知我们。所以我们无法防止崩溃。
您可以在下面找到我们正在使用的代码
var error:NSError? = nil
let dataToUse = NSJSONSerialization.JSONObjectWithData(receivedData, options: NSJSONReadingOptions.AllowFragments, error:&error) as NSDictionary
if error != nil { println( "There was an error in NSJSONSerialization") }
到目前为止我们还找不到解决方法。
问题是您将 JSON 反序列化的结果投射到 之前 检查错误。如果 JSON 数据无效(例如不完整)则
NSJSONSerialization.JSONObjectWithData(...)
returns nil
和
NSJSONSerialization.JSONObjectWithData(...) as NSDictionary
会崩溃。
这是一个正确检查错误条件的版本:
var error:NSError? = nil
if let jsonObject: AnyObject = NSJSONSerialization.JSONObjectWithData(receivedData, options: nil, error:&error) {
if let dict = jsonObject as? NSDictionary {
println(dict)
} else {
println("not a dictionary")
}
} else {
println("Could not parse JSON: \(error!)")
}
备注:
- 检查错误的正确方法是测试 return 值 ,而不是测试 错误变量。
JSON 阅读选项
.AllowFragments
在这里没有帮助。设置这个选项 只允许不是NSArray
或NSDictionary
实例的顶级对象,例如{ "someString" }
您也可以在一行中完成,使用 可选类型转换 as?
:
if let dict = NSJSONSerialization.JSONObjectWithData(receivedData, options: nil, error:nil) as? NSDictionary {
println(dict)
} else {
println("Could not read JSON dictionary")
}
缺点是在else
情况下无法区分是否阅读
JSON 数据失败或者 JSON 不代表字典。
有关 Swift 3 的更新,请参阅
更新 Swift 3
let jsonData = Data()
do {
let jsonObject = try JSONSerialization.jsonObject(with: jsonData, options:JSONSerialization.ReadingOptions(rawValue: 0))
guard let dictionary = jsonObject as? Dictionary<String, Any> else {
print("Not a Dictionary")
// put in function
return
}
print("JSON Dictionary! \(dictionary)")
}
catch let error as NSError {
print("Found an error - \(error)")
}
Swift 2
let JSONData = NSData()
do {
let JSON = try NSJSONSerialization.JSONObjectWithData(JSONData, options:NSJSONReadingOptions(rawValue: 0))
guard let JSONDictionary: NSDictionary = JSON as? NSDictionary else {
print("Not a Dictionary")
// put in function
return
}
print("JSONDictionary! \(JSONDictionary)")
}
catch let JSONError as NSError {
print("\(JSONError)")
}
这是一个 Swift 2 扩展,您可以使用它来反序列化一个 NSDictionary:
extension NSJSONSerialization{
public class func dictionaryWithData(data: NSData, options opt: NSJSONReadingOptions) throws -> NSDictionary{
guard let d: NSDictionary = try self.JSONObjectWithData(data, options:opt) as? NSDictionary else{
throw NSError(domain: NSURLErrorDomain, code: NSURLErrorCannotParseResponse, userInfo: [NSLocalizedDescriptionKey : "not a dictionary"])
}
return d;
}
}
抱歉,我不确定如何进行保护 return 以避免创建临时文件 'd'。
Swift 3 NSJSONSerialization 示例(从文件中读取 json):
file data.json (example from here: http://json.org/example.html)
{
"glossary":{
"title":"example glossary",
"GlossDiv":{
"title":"S",
"GlossList":{
"GlossEntry":{
"ID":"SGML",
"SortAs":"SGML",
"GlossTerm":"Standard Generalized Markup Language",
"Acronym":"SGML",
"Abbrev":"ISO 8879:1986",
"GlossDef":{
"para":"A meta-markup language, used to create markup languages such as DocBook.",
"GlossSeeAlso":[
"GML",
"XML"
]
},
"GlossSee":"markup"
}
}
}
}
}
file JSONSerialization.swift
extension JSONSerialization {
enum Errors: Error {
case NotDictionary
case NotJSONFormat
}
public class func dictionary(data: Data, options opt: JSONSerialization.ReadingOptions) throws -> NSDictionary {
do {
let JSON = try JSONSerialization.jsonObject(with: data , options:opt)
if let JSONDictionary = JSON as? NSDictionary {
return JSONDictionary
}
throw Errors.NotDictionary
}
catch {
throw Errors.NotJSONFormat
}
}
}
用法
func readJsonFromFile() {
if let path = Bundle.main.path(forResource: "data", ofType: "json") {
if let data = NSData(contentsOfFile: path) as? Data {
do {
let dict = try JSONSerialization.dictionary(data: data, options: .allowFragments)
print(dict)
} catch let error {
print("\(error)")
}
}
}
}
结果(日志截图)
Swift 3:
let jsonData = Data()
do {
guard let parsedResult = try JSONSerialization.jsonObject(with: jsonData, options: .allowFragments) as? NSDictionary else {
return
}
print("Parsed Result: \(parsedResult)")
} catch {
print("Error: \(error.localizedDescription)")
}