纯Swift项目-JSON(Basic.frameworks)

Swift JSON 发展史

  1. 最开始的时候仍是使用NSJSONSerialization转成字典和数组来使用!
  2. 后来苹果用Swift从新实现了JSONSerialization能够避免用NSArrayNSDictionary来桥接,提升解析效率。
  3. 随后不少三方JSON库相继出现,例如:SwiftyJSONHandyJSON......等,请原谅我一直没有用过这些三方库,虽然有参考学习过,但我一直维护改进本身封装的JSON库,这期间虽然使用JSON的简便性有所提升,但我仍然以为很麻烦。
  4. Swift 4.0 开始,苹果提供了Codable协议和JSONDecoderJSONEncoder,这一改进使得一众三方库黯然失色,将JSON到模型的便捷方式提高到了一个新的高度,但这种方式仍是过于强硬,模型类型过于死板,稍有不慎就会由于类型不符致使解析失败,所以我将本身的JSON库添加了Codable协议支持,做为官方库的一个有益补充。
  5. Swift 4.2 的时候dynamicMemberLookup(动态属性)的加入又给(软)JSON模型加了一剂强心针。

例子JSON

{"name":"小王","age":5,"reads":["格林童话","安徒生童话"]}git

之前的三方JSON库的缺陷

之前的三方JSON库在将相对动态的json数据解析到模型的时候除了要写属性类型外,在构造方法中,也要写上对应的key,模型写起来很啰嗦,例如:github

struct User {
    var name:String
    var age:Int
    var reads:[String]
    
    init(_ json:JSON) {
        name = json["name"].string
        age = json["age"].int
        reads = json["reads"].array
    }
}
复制代码

属性越多,构造方法中写的也越多,相同的键字符串和变量名显得十分啰嗦json


JSONDecoder 的缺陷

自从苹果革命性的增长了Codable协议,如今只须要写模型的属性,而没必要写构造方法swift

struct User: Codable {
    var name:String
    var age:Int
    var reads:[String]
}
复制代码

解析的时候也十分简便后端

let user = try! JSONDecoder().decode(User.self, from: data)
复制代码

多是由于苹果做为大公司,有着极度严苛的编码规范和先后端协做标准,所以JSONDecoder对类型的要求是十分严苛的,若是换成下面这段JSON内容就会解析失败:数组

{"name":"小王","age":"5","reads":["格林童话","安徒生童话"]}服务器

这其中将age的类型变成了字符串的"5"与模型的Int类型不符,使得整个JSON都没法解析。实际的开发中先后端未必有那么严苛的规范,也不必定总能碰到靠谱的后端,所以常常由于各类类型不符缘由解析模型失败就很蛋疼。网络


可能您会说这只是小问题,只要规范开发就行了,那下面这个问题就是硬伤。


好比说通常状况下后端给咱们返回的JSON都有几个固定字段判断返回结果可用性,例如:post

{
    "errorCode":0,
    "errorMessage":"成功",
    "result":{}
}
复制代码
{
    "errorCode":1,
    "errorMessage":"缺乏参数",
    "result":null
}
复制代码

在上面的例子中errorCode是服务器返回的错误状态0表示请求成功errorMessage是错误状态提示文本,result根据不一样的API接口,返回不一样格式的JSON内容。 若是想写一个模型的话:学习

struct ResponseJSON: Codable {
    var errorMessage: String
    var errorCode: Int
    var result: ???????
}
复制代码

这就尴尬了,result属性的类型无法填,由于没法肯定此刻它该使用什么模型。 解决方法以下:

  1. 不使用模型,改用字典,但这样就回归原始,用起来不方便。
  2. result属性类型使用[String:Any],虽然当下使用了模型,但后面使用很不方便。
  3. ResponseJSON使用泛型定义由调用网络请求接口预传入result所需的模型
  4. 定义一种动态类型保存未彻底解析的JSON,允许对应接口使用result字段时懒解析到恰当的模型

其中,比较好的方法是34, 但方法3仍是有缺陷,相同的API返回的JSON结构就必定相同么?可能有一个type属性表示着另外一个属性是什么结构。这种时候,预传入泛型就无能为力了。

所以咱们须要定义一个符合Codable协议的动态类型来保存未彻底解析的JSON, 在须要的时候能够懒解析成所需模型。

public enum JSON: Codable {
    case object (Object)
    case array  (Array)
    case string (String)
    case number (Number)
    case bool   (Bool)
    case null
    case error  (Error, ignore:[String])
}
复制代码

代码固然不止这点,详细内容能够参考(Basic.frameworks)中关于JSON的部分

  • 如今,咱们能够将ResponseJSON定义成:
struct ResponseJSON: Codable {
    var errorMessage: String
    var errorCode: Int
    var result: JSON
}
复制代码

在须要的时候使用

let user = try! JSON.Decoder().decode(User.self, from: responseJSON.result)
复制代码

或者其余模型


  • 前例(JSON)中objectarraystringnumberboolnull这6个是咱们熟知的json数据类型,而error是什么呢?为何要添加它?

顾名思义,error就是错误,添加一个错误类型是用来代替属性获取可选链。

  • 若是没有error,咱们的JSON应该是这样使用的。
var json:JSON = .....
let name = json.result?.list?[0].name?.string
复制代码

这种方式是利用可选链?来传递属性,若是其中一个属性不存在,不会报错,而是获得一个nil值,通常状况这样已经足够,但若是出现错误的json,想要排查问题就须要逐层查看或测试,错误信息在可选链的第几层彻底丢失。

如今加入了error (Error, ignore:[String])类型,就无需使用可选链来传递属性了

var json:JSON = .....
let name = json.result.list[0].name.string
复制代码

当某个属性没法获取时,能够给Error类型,并且还能够传递下去,而且不会丢失错误信息。最终转换string或者int时,能够根据开发环境和生产环境,选择中断或者返回默认值!

JSONDecoder 和 JSON.Decoder 的区别

  • JSONDecoder 是苹果官方提供的将二进制JSON解析成模型Model的解析类
  • JSON.Decoder是(Basic.frameworks)中仿照官方方法,将二进制或JSON软模型解析成模型Model的解析类

JSON解析关系图
如图所示,不一样线条样式表明不一样的数据流向来源

  1. 他们的做用类似,只是JSON.Decoder削弱了数据类型的强制要求,
  2. JSON.Decoder提供了比官方JSONDecoder更多的解析策略,
  3. JSON.Decoder为了方便提供了全局策略默认值的修改。

流向总结

  1. DataString能够经过官方的JSONDecoder或(Basic.frameworks)中的JSON.Decoder解析到实现Codable协议的Model模型
  2. DataString能够经过(Basic.frameworks)中的JSON.Decoder或解析到JSON软模型、Model模型或二者混合
  3. JSON软模型能够经过(Basic.frameworks)中的JSON.Decoder解析到Model模型或混合模型。
  4. Model模型或混合模型能够经过(Basic.frameworks)中的JSON.Encoder系列化成JSON软模型,或Data二进制
  5. Model模型或混合模型能够经过官方的JSONEncoder系列化成Data二进制
  6. JSON软模型能够经过官方的JSONEncoder或(Basic.frameworks)中的JSON.Encoder系列化成Data二进制

实际使用实例

参见文章《纯Swift项目-HTTP(Basic.frameworks)》一文中的例子

相关文章
相关标签/搜索