美文网首页
Swift5 原生JSON对象转Model & 简易封装

Swift5 原生JSON对象转Model & 简易封装

作者: Fatm | 来源:发表于2020-03-10 14:58 被阅读0次

    JSON对象转Model其实是一个编解码的过程,Swift原生提供Codable协议负责编解码的工作,遵循协议的对象可以使用JSONEncoder进行编码,使用JSONDecoder进行解码。

    概述:
    JSONSerialization:用于Foundation类型与Data的转换
    JSONDecoder:解码Data->Model类型
    JSONEncoder:编码Model类型->Data
    Codable协议:解码协议Decodable & 编码协议Encodable 的别名

    原理:
    1.通过JSONSerialization可以把字典/数组对象序列化成Data
    2.使用JSONDecoder把Data解码成相应的Model类型,Model需遵循Codable协议。

    DEMO下载地址

    演示 playground

    class Student:NSObject,Codable{
        var name: String?
        var age: Int?
    }
    
    let jsonObject:[String:Any] = ["name":"xiaohua","age":23]
    
    let data = try JSONSerialization.data(withJSONObject: jsonObject, options: [])
    let student:Student = try JSONDecoder().decode(Student.self, from: data)
    
    print(student.name ?? "")  
    

    打印结果:
    "xiaohua"

    Codable使用起来很简约👆

    简易封装

    每次使用时都写一次编解码的过程效率不高,所以这里把序列化解码的代码封装到一个类方法里,用范型<T>来指代要转换成的Model类型

    演示 DFJsonKit.swift

    static func jsonToModel<T:Codable>(withJSONObject obj:Any?,modelType:T.Type)->T?
    

    ·转换失败返回nil
    ·转换成功返回对应的model

    static func jsonToModel<T:Codable>(withJSONObject obj:Any?,modelType:T.Type)->T?{
        /*
         jsonObject->data->model
         */
        
        guard let obj = obj else {
            return nil
        }
        do{
            let jsonData = try JSONSerialization.data(withJSONObject: obj as Any, options:[])
            let model = try JSONDecoder().decode(modelType, from: jsonData)
            return model
        }catch{
            print(error)
            return nil
        }
    }
    

    用的时候传入JSON对象(字典/数组)和Model类型:

    let student = DFJsonKit.jsonToModel(withJSONObject: jsonObject, modelType: Student.self)
    print(student?.name ?? "")
    

    打印结果:
    "xiaohua"

    这样使用的时候方便很多

    Data、jsonObject、model和string之间的转换关系

    wkWebView与web端交互的时候,偶尔会遇到上传json字符串或者接收一个json字符串转换成model的情况,这时可以根据图上的转化关系,把相应的model转成string传给web端,或者把web端的string转成model

    参考JSONObjectmodel的封装方式,把Data,jsonObject,model,string之间的相互转换都封装到一起,用起来就方便许多👇
    DEMO下载地址

    延伸

    苹果提供了一个CodingKeys枚举来支持一些自定义的实现

    1.只转换Model中的部分字段:
    这里只想要age,把age单独加到CodingKeys枚举中

    class Student:NSObject,Codable{
        var name: String?
        var age: Int?
        
        enum CodingKeys:String, CodingKey {
            case age
        }
    }
    
    let jsonObject:[String:Any] = ["nickName":"xiaohua","age":23]
    
    let student = DFJsonKit.jsonToModel(withJSONObject: jsonObject, modelType: Student.self)
    print(student?.name ?? "没有转换所以没有")
    print(student?.age ?? 0)
    

    打印结果:
    "没有转换所以没有"
    "23"

    2.数据源中的Key与Model中Key字段不同:
    数据源中姓名字段是nickName,Model中是name。在CodingKeys枚举中把nickName赋值给name,让Codable处理的时候使用nickName字段

    class Student:NSObject,Codable{
        var name: String?
        var age: Int?
        
        enum CodingKeys:String, CodingKey {
            case name = "nickName"
            case age
        }
    }
    
    let jsonObject:[String:Any] = ["nickName":"xiaohua","age":23]
    
    let student = DFJsonKit.jsonToModel(withJSONObject: jsonObject, modelType: Student.self)
    print(student?.name ?? "")
    print(student?.age ?? 0)
    

    打印结果:
    "xiaohua"
    "23"

    3.如果数据源是model数组:

    Demo 一组数据源

    let jsonObject = [["name":"xiaohua","age":23],["name":"xiaoming","age":22]]
    let studentArray = DFJsonKit.jsonToModel(withJSONObject: jsonObject, modelType: Array<Student>.self)
    
    studentArray?.forEach({ (student) in
        print(student.name ?? "")
        print(student.age ?? 0)
    })
    

    打印结果:
    "xiaohua"
    "23"
    "xiaoming"
    "22"

    4.服务端使用蛇形命名方式而客户端使用的是驼峰:
    Swift 4.1 中的 Codable 改进

    DEMO下载地址

    相关文章

      网友评论

          本文标题:Swift5 原生JSON对象转Model & 简易封装

          本文链接:https://www.haomeiwen.com/subject/eyewdhtx.html