Swift JSONSerialization

1,064 阅读5分钟

JSONSerialization

JSONSerialization是swift提供的将 JSON 转换为 Foundation 对象并将 Foundation 对象转换为 JSON 的类。同Object-c的NSJSONSerialization,俗称:序列化

  • 序列化:将对象的状态信息转换为可以存储或传输的形式的过程。在序列化期间,对象将其当前状态写入到临时或持久性存储区。可以理解为将数据结构或对象转换成二进制串的过程
  • 反序列化:可以通过从存储区中读取或反序列化对象的状态,重新创建该对象。可以理解为将在序列化过程中所生成的二进制串转换成数据结构或者对象的过程

官方描述

  /* 
   A class for converting JSON to Foundation objects and converting Foundation objects to JSON.
   An object that may be converted to JSON must have the following properties:
    - Top level object is an NSArray or NSDictionary
    - All objects are NSString, NSNumber, NSArray, NSDictionary, or NSNull
    - All dictionary keys are NSStrings
    - NSNumbers are not NaN or infinity
  */
  用于将JSON转换为Foundation对象和将Foundation对象转换为JSON的类。
    一个可以被转换为JSON的对象必须具有以下属性:
    —顶级对象是NSArrayNSDictionary
    —所有对象都是NSStringNSNumberNSArrayNSDictionaryNSNull
    —所有的字典键都是nsstring
    —NSNumber不是NaN或infinity
  

1. 判断对象是否可以转换为JSON数据

/* Returns YES if the given object can be converted to JSON data, NO otherwise. The object must have the following properties:
        - Top level object is an NSArray or NSDictionary
        - All objects are NSString, NSNumber, NSArray, NSDictionary, or NSNull
        - All dictionary keys are NSStrings
        - NSNumbers are not NaN or infinity
     Other rules may apply. Calling this method or attempting a conversion are the definitive ways to tell if a given object can be converted to JSON data.

     */
   *如果给定的对象可以转换为JSON数据,则返回YES,否则返回NO。对象必须具有以下属性:
        —顶级对象是NSArrayNSDictionary
        —所有对象都是NSStringNSNumberNSArrayNSDictionaryNSNull
        —所有的字典键都是nsstring
        —nsnumber不是NaN或infinity
    其他规则也可能适用。调用此方法或尝试转换是确定给定对象是否可以转换为JSON数据的决定性方法。

    open class func isValidJSONObject(_ obj: Any) -> Bool

2. 从 Foundation 对象生成 JSON 数据

 /* Generate JSON data from a Foundation object. If the object will not produce valid JSON then an exception will be thrown. Setting the NSJSONWritingPrettyPrinted option will generate JSON with whitespace designed to make the output more readable. If that option is not set, the most compact possible JSON will be generated. If an error occurs, the error parameter will be set and the return value will be nil. The resulting data is a encoded in UTF-8.
    从一个Foundation对象生成JSON数据。如果对象不能生成有效的JSON,则会抛出一个异常。设置NSJSONWritingPrettyPrinted选项将生成带有空格的JSON,以使输出更具可读性。如果没有设置该选项,将生成尽可能紧凑的JSON。如果发生错误,将设置error参数,并且返回值为nil。结果数据是用UTF-8编码的
    
    open class func data(withJSONObject obj: Any, options opt: JSONSerialization.WritingOptions = []) throws -> Data

3. 从JSON数据创建一个Foundation对象

    /* Create a Foundation object from JSON data. Set the NSJSONReadingAllowFragments option if the parser should allow top-level objects that are not an NSArray or NSDictionary. Setting the NSJSONReadingMutableContainers option will make the parser generate mutable NSArrays and NSDictionaries. Setting the NSJSONReadingMutableLeaves option will make the parser generate mutable NSString objects. If an error occurs during the parse, then the error parameter will be set and the result will be nil.

       The data must be in one of the 5 supported encodings listed in the JSON specification: UTF-8, UTF-16LE, UTF-16BE, UTF-32LE, UTF-32BE. The data may or may not have a BOM. The most efficient encoding to use for parsing is UTF-8, so if you have a choice in encoding the data passed to this method, use UTF-8.

     */
     /*从JSON数据创建一个Foundation对象。如果解析器应该允许非NSArray或NSDictionary的顶级对象,则设置NSJSONReadingAllowFragments选项。设置nsjsonreadingmutableccontainers选项将使解析器生成可变的NSArrays和nsdictionary。设置NSJSONReadingMutableLeaves选项将使解析器生成可变的NSString对象。如果在解析期间发生错误,则将设置error参数,结果将为nil。
       数据必须是JSON规范中列出的5种支持的编码之一:UTF-8, UTF-16LE, UTF-16BE, UTF-32LE, UTF-32BE。数据可能有BOM,也可能没有。用于解析的最有效编码是UTF-8,因此,如果可以选择对传递给该方法的数据进行编码,请使用UTF-8。
     */
     
     open class func jsonObject(with data: Data, options opt: JSONSerialization.ReadingOptions = []) throws -> Any

4.将JSON数据写入流

    /* 
      Write JSON data into a stream. The stream should be opened and configured. The return value is the number of bytes written to the stream, or 0 on error. All other behavior of this method is the same as the dataWithJSONObject:options:error: method.
     */
     /*
      将JSON数据写入流。应该打开并配置流。返回值是写入流的字节数,或者在出错时为0。该方法的所有其他行为都与dataWithJSONObject:options:error:方法相同。
      */
      
      open class func writeJSONObject(_ obj: Any, to stream: OutputStream, options opt: JSONSerialization.WritingOptions = [], error: NSErrorPointer) -> Int

5.从JSON数据流创建JSON对象

    /* 
    Create a JSON object from JSON data stream. The stream should be opened and configured. All other behavior of this method is the same as the JSONObjectWithData:options:error: method.
     */
    /*
     从JSON数据流创建JSON对象。应该打开并配置流。该方法的所有其他行为都与JSONObjectWithData:options:error:方法相同。
     */
     
     open class func jsonObject(with stream: InputStream, options opt: JSONSerialization.ReadingOptions = []) throws -> Any
     

JSON解析

    func jsonSerialization() {
        let data = readLocalJsonFile()
        do {
            let dit = try JSONSerialization.jsonObject(with: data as Data, options: JSONSerialization.ReadingOptions.mutableContainers)
            print("jsonSerialization:\(dit)")
        } catch  {
            print("jsonSerialization error")
        }
    }
    /* 成功解析成了字典
    jsonSerialization:{
        code = 0;
        data =     {
            ......
            }
        }
    */

大多数json库底层都使用JSONSerialization进行数据反序列化,把数据转换成字典或者数组类型。然后通过runtime获取属性,kvc进行负值,这是大多数oc库中json转model的底层逻辑

1. 明明swift中数组,字典使用很方便了(怀恋js中数据搞的很方便),不直接使用Dictionary当作数据源去操作?

    func jsonSerialization() {
        let data = readLocalJsonFile()
        do {
            let dit:Dictionary<String, Any> = try JSONSerialization.jsonObject(with: data as Data, options: JSONSerialization.ReadingOptions.mutableContainers) as! Dictionary<String, Any>
            let dataDit = dit["data"]
            let array: [Any?] = dataDit["list"] // 报错 Value of type 'Any?' has no subscripts
            print("jsonSerialization:\(dit)")
        } catch  {
            print("jsonSerialization error")
        }
    }
    

直接使用的话,你会发现在多层次情况下,简直是地狱,数据类型,解包,可选类型很麻烦,你看着代码没问题,但是就是报错,你也不知道改如何处理