【问题标题】:Swift, NSJSONSerialization and NSErrorSwift、NSJSONSerialization 和 NSError
【发布时间】:2015-03-11 00:14:21
【问题描述】:

问题是当数据不完整时,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") }

到目前为止,我们无法找到解决方法。

【问题讨论】:

    标签: swift nsjsonserialization nserror


    【解决方案1】:

    问题是您将 JSON 反序列化的结果转换为 before 检查错误。如果 JSON 数据无效(例如不完整),则

    NSJSONSerialization.JSONObjectWithData(...)
    

    返回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!)")
    }
    

    备注:

    • 检查错误的正确方法是测试返回值,而不是 错误变量。
    • JSON 读取选项.AllowFragments 在这里没有帮助。设置此选项 只允许顶级对象不是NSArrayNSDictionary 的实例,例如

      { "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 的更新,请参阅 LightningStryk's answer

    【讨论】:

    • 您解释为“这是一个正确检查错误条件的版本”的部分也没有捕获错误。不幸的是,它在这条线上被压碎了让 dataToUse: AnyObject = NSJSONSerialization.JSONObjectWithData(receivedData, options: NSJSONReadingOptions.AllowFragments, error:&error)!我想说的是,如果收到的数据没有问题,我提交的这个代码和以前的代码都可以正常工作。
    • @Hope:这不是我所建议的。如果你用! 强制解包结果,那么你会遇到与强制转换as NSDictionary 相同的问题:如果结果为nil,它将崩溃。
    • 让 dataToUse: AnyObject? = NSJSONSerialization.JSONObjectWithData(receivedData, options: NSJSONReadingOptions.AllowFragments, error:&error) 似乎没问题。所以我正在检查你回答的问题。至少你对这个主题的把握更好。
    【解决方案2】:

    为 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)")
    }
    

    斯威夫特 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)")
    }
    

    【讨论】:

    • ouch swift 与 objc 相比确实有一个糟糕的语法。 “let”、“do”、“try”、“guard”、“as?”、“catch”……这么多行话。
    • 如果你能捕获运行时异常,因为它无法转换为 NSDictionary,那就更好了,不敢相信他们必须添加一个全新的关键字保护才能使这成为可能。
    • 使用大写的首字母作为变量名是个坏主意,你会让人们感到困惑。但同时,感谢您的回答。
    • 如果变量是首字母缩写词(例如 JSON、URL 等)我更喜欢将整个单词大写,否则看起来很奇怪(jSON、uRL)
    【解决方案3】:

    这是一个 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;
        }
    }
    

    抱歉,我不确定如何进行后卫返回以避免创建临时“d”。

    【讨论】:

      【解决方案4】:

      Swift 3 NSJSONSerialization 示例(从文件中读取 json):

      文件 data.json(此处的示例: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"
              }
          }
      }
      }
      }
      

      文件 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)")
                  }
      
              }
          }
      }
      

      结果(日志截图)

      【讨论】:

        【解决方案5】:

        斯威夫特 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)")
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2018-10-05
          • 1970-01-01
          • 1970-01-01
          • 2015-06-26
          • 1970-01-01
          • 1970-01-01
          • 2016-01-14
          • 2016-05-14
          相关资源
          最近更新 更多