博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
swift之字典转模型kvc、mjextention桥接、反射、HandyJSON、ObjectMapper、Codable
阅读量:4290 次
发布时间:2019-05-27

本文共 19504 字,大约阅读时间需要 65 分钟。

参考swift4.0字典转模型:https://www.cnblogs.com/shaoting/p/8087153.html

 

 

=====================kvc字典转模型=========================

*****第一层模型import UIKitclass LYBHomeLunboModel: NSObject {    @objc var name:String?="11"         @objc var age:NSNumber?    @objc var phones:[LYBPhonesModel]? init(dict:[String:Any]) {        super.init()         setValuesForKeys(dict)    }    override func setValue(_ value: Any?, forKey key: String) {                if key=="phones"{            let temp = value as! [AnyObject]                var resultArray = [LYBPhonesModel]()                for dict in temp {                resultArray.append(LYBPhonesModel(dict: dict as! [String : AnyObject]))                    }            phones = resultArray            return                    }        super.setValue(value, forKey: key)    }    override func setValue(_ value: Any?, forUndefinedKey key: String) {    }       }*****************第二层模型*********import UIKitclass LYBPhonesModel: NSObject {   @objc var name:String?   @objc var number:String?        init(dict: [String: AnyObject]) {        super.init()                setValuesForKeys(dict)    }        override func setValue(_ value: Any?, forKey key: String) {        super.setValue(value, forKey: key)    }    override func setValue(_ value: Any?, forUndefinedKey key: String) {            }}*****************//kvc    func swiftkvc(){      //1.这是一个JSON字符串        let jsonStr = "[{\"name\": \"hangge\", \"age\": 100, \"phones\": [{\"name\": \"公司\",\"number\": \"123456\"}, {\"name\": \"家庭\",\"number\": \"001\"}]}, {\"name\": \"big boss\",\"age\": 1,\"phones\": [{ \"name\": \"公司\",\"number\": \"111111\"}]}]"                //2.吧JSON字符串变成data数据        if let jsonData = jsonStr.data(using: String.Encoding.utf8, allowLossyConversion: false) {              //***************系统的序列化成json*************            do{//                //3.吧jsondata转换成JSON对象(即字典,或字典数组)                if  let dictArr:[[String:Any]]=(tryJSONSerialization.jsonObject(with:jsonData , options: .allowFragments)as?[[String : Any]])  {                    let dict:[String:Any]=dictArr[1]                    let model:LYBHomeLunboModel=LYBHomeLunboModel(dict:dict)                                        print("\(model.phones![0].name!)")                }            }        catch {            }            }

 

================================MJExtention桥接字典转模型================================

 

1.这是一个JSON字符串//let jsonStr = "//[//{\"name\": \"hangge\",//\"age\": 100,//\"phones\"://    [//    {//        \"name\": \"公司\",//    \"number\": \"123456\"////    },//    {//        \"name\": \"家庭\",//        \"number\": \"001\"////    }//    ]//},//{//    \"name\": \"big boss\",//    \"age\": 1,//    \"phones\"://    [//    {//        \"name\": \"公司\",//    \"number\": \"111111\"////    }//    ]////}//    ]"#import 
#import
@interface LYBmjextentionTofirstModel : NSObject@property(nonatomic,copy)NSString *name;@property(nonatomic,copy)NSString *age;@property(nonatomic,strong)NSArray *phones;@end****************#import "LYBmjextentionTofirstModel.h"#import "LYBmjextentionModelTosec.h"@implementation LYBmjextentionTofirstModel+ (NSDictionary *)mj_objectClassInArray{    return@{@"phones" : [LYBmjextentionModelTosecclass]};}@end*******************#import
#import
@interface LYBmjextentionModelTosec : NSObject@property(nonatomic,copy)NSString *name;@property(nonatomic,copy)NSString *number;@end************************#import "LYBmjextentionModelTosec.h"@implementation LYBmjextentionModelTosec@end**************************swift的桥接文件中#import
#import "LYBmjextentionTofirstModel.h"**************在VC中使用: //1.这是一个JSON字符串        let jsonStr ="[{\"name\": \"hangge\", \"age\": 100, \"phones\": [{\"name\": \"公司\",\"number\": \"123456\"}, {\"name\": \"家庭\",\"number\": \"001\"}]}, {\"name\": \"big boss\",\"age\": 1,\"phones\": [{ \"name\": \"公司\",\"number\": \"111111\"}]}]"                //2.吧JSON字符串变成data数据        if let jsonData = jsonStr.data(using:String.Encoding.utf8, allowLossyConversion:false) {//**************swiftyjson*吧json的data数据序列化成json对象然后mjextention转模型****************不用担心数组越界,不用判断节点,拆包什么的                       do{//序列化成JSON对象                let json = try JSON(data: jsonData, options:.allowFragments)                let dict=json[0]               let fm=LYBmjextentionTofirstModel.mj_object(withKeyValues:dict)或者print(fm)                let model:LYBmjextentionTofirstModel=LYBmjextentionTofirstModel()                model.mj_setKeyValues(dict)                print(model)                print("\(model.name)")            }catch{                           }                    }

==================反射字典转模型=========

参考:http://swift.gg/2015/11/23/swift-reflection-api-what-you-can-do/#custom_mirrors

https://www.jianshu.com/p/3d0dba5f781a

 

所谓反射就是可以动态获取类型、成员信息,同时在运行时(而非编译时)可以动态调用任意方法、属性等行为的特性。

Swift的反射机制是基于一个叫Mirror的struct来实现的,其内部有如下属性和方法:

let children: Children  //对象的子节点。displayStyle: Mirror.DisplayStyle?   //对象的展示风格let subjectType: Any.Type  //对象的类型func superclassMirror() -> Mirror?   //对象父类的基于上面mjextention中的模型来实现:  let model:LYBmjextentionTofirstModel=LYBmjextentionTofirstModel()            model.name="名字"                model.age="18"                //将model进行反射                let aMirror = Mirror(reflecting: model)                print("对象类型:\(aMirror.subjectType)")                print("对象子元素的个数:\(aMirror.children.count)")                print("对象的展示风格:\(aMirror.displayStyle)")                     *******************        

=======================HandyJSON==============阿里巴巴出的

 

下载地址:https://github.com/alibaba/handyjson

 

参考:https://www.cnblogs.com/crazyacking/p/5927909.html?hmsr=toutiao.io&utm_medium=toutiao.io&utm_source=toutiao.io

采用Swift反射+内存赋值的方式来构造Model实例,保持原汁原味的Swift类定义

在Swift中把JSON反序列化到Model类,在HandyJSON出现以前,主要使用两种方式:

  1. 让Model类继承自NSObject,然后class_copyPropertyList()方法获取属性名作为Key,从JSON中取得Value,再通过Objective-C runtime支持的KVC机制为类属性赋值;如JSONNeverDie

  2. 支持纯Swift类,但要求开发者实现Mapping函数,使用重载的运算符进行赋值,如ObjectMapper

这两者都有显而易见的缺点。前者要求Model继承自NSObject,非常不优雅,且直接否定了用struct来定义Model的方式;后者的Mapping函数要求开发者自定义,在其中指明每个属性对应的JSON字段名,代码侵入大,且仍然容易发生拼写错误、维护困难等问题。

***注意:swift4.0,在用cocoapods引入的时候,需要注明版本pod 'HandyJSON','4.0.0-beta.1'

 

HandyJSON支持在类定义里使用各种形式的基本属性,包括可选(?),隐式解包可选(!),数组(Array),字典(Dictionary),Objective-C基本类型(NSString、NSNumber),各种类型的嵌套([Int]?、[String]?、[Int]!、...)等等

 

使用举例:1.***********简单的json字符串(字符串中是纯json格式):import UIKitimport HandyJSONclass LYBHandyJsononeModel: HandyJSON {//模型类需要继承HandyJSON    @objc var name:String?    @objc var age:NSNumber?     required init() {}// 如果定义是struct,连init()函数都不用声明;}使用: let jsonStr="{\"name\": \"hangge\", \"age\": 100}"                  //2.吧JSON字符串变成data数据        if let jsonData = jsonStr.data(using: String.Encoding.utf8, allowLossyConversion: false) {              //***************系统的序列化成json*************            do{//                //3.吧jsondata转换成JSON对象(即字典,或字典数组)                if  let dict:[String:Any]=(try JSONSerialization.jsonObject(with:jsonData , options: .allowFragments)as?[String : Any])  {                   let model=JSONDeserializer
.deserializeFrom(dict: dict) print((model?.name)!) } } catch { }

3.***************---json字符串中的最外层是数组

import UIKitimport HandyJSONclass LYBHandyJsononeModel: HandyJSON {    @objc var name:String?    @objc var age:String?     required init() {}// 如果定义是struct,连init()函数都不用声明;}

 

 使用:

//1.这是一个JSON字符串,字符串中最外层是数组        let jsonStr = "[{\"name\": \"hangge\", \"age\": 100, \"phones\": [{\"name\": \"公司\",\"number\": \"123456\"}, {\"name\": \"家庭\",\"number\": \"001\"}]}, {\"name\": \"big boss\",\"age\": 15,\"phones\": [{ \"name\": \"公司\",\"number\": \"111111\"}]}]"        let model=JSONDeserializer
.deserializeModelArrayFrom(json: jsonStr) print((model?[0]?.age)!)

4.***********json字符串,最外层是数组,数组中的内容是字典

 

 

import UIKitimport HandyJSONclass LYBHandyJsononeModel: HandyJSON {    @objc var name:String?    @objc var age:String?     required init() {}// 如果定义是struct,连init()函数都不用声明;}
//1.这是一个JSON字符串,字符串中最外层是数组        let jsonStr = "[{\"name\": \"hangge\", \"age\": 100, \"phones\": [{\"name\": \"公司\",\"number\": \"123456\"}, {\"name\": \"家庭\",\"number\": \"001\"}]}, {\"name\": \"big boss\",\"age\": 15,\"phones\": [{ \"name\": \"公司\",\"number\": \"111111\"}]}]"

 

 

使用:

//2.吧JSON字符串变成data数据        if let jsonData = jsonStr.data(using: String.Encoding.utf8, allowLossyConversion: false) {              //***************系统的序列化成json*************            do{//                //3.吧jsondata转换成JSON对象(即字典,或字典数组)                if  let dictArr:[[String:Any]]=(try JSONSerialization.jsonObject(with:jsonData , options: .allowFragments)as?[[String : Any]])  {                   let model=JSONDeserializer
.deserializeModelArrayFrom(array: dictArr) print((model![0]?.name)!) } } catch { } let model=JSONDeserializer
.deserializeModelArrayFrom(array: dictArr) print((model![0]?.name)!) } } catch { }

===========字典数组转模型1=========

/*             {             msg = "\U83b7\U53d6\U6210\U529f";             result =     {             ad =         (             {             "ad_code" = "http://www.ddb.cn/public/upload/ad/2018/07-24/f1278a99a637ff4db766e94339dec180.jpg";             "ad_link" = "https://mp.weixin.qq.com/s/x1JPnh5qXl0bkyvN5EcvrA";             "ad_name" = "\U4fe1\U7528\U5361\U57ab\U8fd8";             },             {             "ad_code" = "http://www.ddb.cn/public/upload/ad/2018/08-22/8b7a59c2924c1813f9e2c5895a02a226.png";             "ad_link" = "https://mp.weixin.qq.com/s/phLc3iHQaU6TyI6hkmfIpg";             "ad_name" = "\U4fe1\U7528\U5361\U529e\U7406";             },             {             "ad_code" = "http://www.ddb.cn/public/upload/ad/2018/11-09/52be0b76b5c4d579cbb3c88d146c6ea0.jpg";             "ad_link" = "https://mp.weixin.qq.com/s/sWM6q5Fi726Ruj73uFZVfg";             "ad_name" = "\U81ea\U5b9a\U4e49\U5e7f\U544a\U540d\U79f0";             }             );             };             status = 1;             }*/            if  ((res["result"]) != nil) {//判断res中是否存在result这个键            let resultDict=res["result"] as! NSDictionary             if  ((res["ad"]) != nil) {                let ad:[[String:AnyObject]]=resultDict.value(forKey: "ad") as! [[String : AnyObject]]                 print("\(ad.count)")                               let model=JSONDeserializer
.deserializeModelArrayFrom(array: ad);//字典数组转成模型数组方法一// let headerScrollModel=[LYBHomeHeaderScrollModel].deserialize(from: ad)// 字典数组转换成模型数组方法二 print("\(String(describing: model?[0]?.ad_link))") } }else { print("没有") }

============字典转模型==============

if  ((res["result"]) != nil) {//判断res中是否存在result这个键            let resultDict=res["result"] as? NSDictionary            let  loginresultModel=LYBLoginResultModel.deserialize(from: resultDict)//这是根据字典转模型,还可以直接字符串转模型            LYBLoginVC.model=loginresultModel//静态变量存储,整个程序生命周期期间且所有类中都可以用            print("\(String(describing: loginresultModel?.token))")        }else{            print("没有")        }

********嵌套转模型*******

lazy var rightdata:[String:[[String:[String]]]]={        let dataDict:[String:[[String:[String]]]]=["leftone":[["headerName":["one第一组"],"images":["icon_shot_sel","icon_shot_sel","icon_shot_sel","icon_shot_sel","icon_shot_sel","icon_shot_sel"]],["headerName":["one第二组"],"images":["comm_btn_checkmark","comm_btn_checkmark","comm_btn_checkmark","comm_btn_checkmark","comm_btn_checkmark","comm_btn_checkmark"]],["headerName":["one第三组"],"images":["comm_btn_checkmark","comm_btn_checkmark","comm_btn_checkmark","comm_btn_checkmark","comm_btn_checkmark","comm_btn_checkmark"]]],                                                   "lefttwo":[["headerName":["two第一组"],"images":["icon_shot_sel","icon_shot_sel","icon_shot_sel","icon_shot_sel","icon_shot_sel","icon_shot_sel"]],["headerName":["two第二组"],"images":["comm_btn_checkmark","comm_btn_checkmark","comm_btn_checkmark","comm_btn_checkmark","comm_btn_checkmark","comm_btn_checkmark"]],["headerName":["two第三组"],"images":["comm_btn_checkmark","comm_btn_checkmark","comm_btn_checkmark","comm_btn_checkmark","comm_btn_checkmark","comm_btn_checkmark"]]],                                                   "leftthree":[["headerName":["three第一组"],"images":["icon_shot_sel","icon_shot_sel","icon_shot_sel","icon_shot_sel","icon_shot_sel","icon_shot_sel"]],["headerName":["three第二组"],"images":["comm_btn_checkmark","comm_btn_checkmark","comm_btn_checkmark","comm_btn_checkmark","comm_btn_checkmark","comm_btn_checkmark"]],["headerName":["three第三组"],"images":["comm_btn_checkmark","comm_btn_checkmark","comm_btn_checkmark","comm_btn_checkmark","comm_btn_checkmark","comm_btn_checkmark"]]]                     ]                return dataDict    }()*******第一层import UIKitclass LYBTabAndCollectionConnectModel: HandyJSON {    var leftone:[LYBrightSecModel]?     var lefttwo:[LYBrightSecModel]?     var leftthree:[LYBrightSecModel]?        required init(){            }}*******第二层import UIKitclass LYBrightSecModel: HandyJSON {    var headerName:[String]?    var images:[String]?    required init(){        }}使用: let  modelDict=LYBTabAndCollectionConnectModel.deserialize(from: rightdata) as! LYBTabAndCollectionConnectModel        print("\(String(describing: modelDict.leftone?.first?.images?.first))")

5.*******************字典中的value是字典或者是数组(数组中的元素是字典),继续创建下一级模型

嵌套的Model类

 

如果Model类中的某个属性是另一个自定义的Model类,那么只要那个Model类也实现了HandyJSON协议,就一样可以转换:

 

//第一层模型import UIKitimport HandyJSONclass LYBHandyJsononeModel: HandyJSON {  var name:String?var age:String?  var phones:[LYBHandyJsonSecModel]? required init() {}// 如果定义是struct,连init()函数都不用声明;}//第二层模型import UIKitimport HandyJSONclass LYBHandyJsonSecModel: HandyJSON {    var name:String?    var age:String?        required init() {}// 如果定义是struct,连init()函数都不用声明;} //1.这是一个JSON字符串,字符串中最外层是数组        let jsonStr = "[{\"name\": \"hangge\", \"age\": 100, \"phones\": [{\"name\": \"公司\",\"number\": \"123456\"}, {\"name\": \"家庭\",\"number\": \"001\"}]}, {\"name\": \"big boss\",\"age\": 15,\"phones\": [{ \"name\": \"公司\",\"number\": \"111111\"}]}]"       [{\"name\": \"hangge\", \"age\": 100, \"phones\": [{\"name\": \"公司\",\"number\": \"123456\"}, {\"name\": \"家庭\",\"number\": \"001\"}]}, {\"name\": \"big boss\",\"age\": 15,\"phones\": [{ \"name\": \"公司\",\"number\": \"111111\"}]}]"

使用:

//2.吧JSON字符串变成data数据
if let jsonData = jsonStr.data(using: String.Encoding.utf8, allowLossyConversion: false) {              //***************系统的序列化成json*************            do{//                //3.吧jsondata转换成JSON对象(即字典,或字典数组)                if  let dictArr:[[String:Any]]=(try JSONSerialization.jsonObject(with:jsonData , options: .allowFragments)as?[[String : Any]])  {                  let model=JSONDeserializer
.deserializeModelArrayFrom(array: dictArr) let phones=model![0]?.phones; print("\((phones![1].name)!)") } } catch { } let model=JSONDeserializer
.deserializeModelArrayFrom(array: dictArr) let phones=model![0]?.phones; print("\((phones![1].name)!)") } } catch { }
6.********************指定反序列化JSON中某个节点(指定路径转模型,可以选择有用的数组转模型,跳过无用的数据)------解析的指定路径要保证唯一性才可以;
这是一个JSON字符串,字符串内只有字典嵌套,可以任意指定路径解析

 

有时候服务端返回给我们的JSON文本包含了大量的状态信息,和Model无关,可以指定反序列化哪个节点:

有继承关系的Model类

如果某个Model类继承自另一个Model类,只需要这个父Model类实现HandyJSON协议就可以:

//第一层模型

import UIKit

import HandyJSON

class LYBHandyJsononeModel: HandyJSON {

  var name:String?

var age:String?

  var phones:LYBHandyJsonSecModel?

 required init() {}// 如果定义是struct,连init()函数都不用声明;

}

*******

//第二层模型

import UIKit

import HandyJSON

class LYBHandyJsonSecModel: HandyJSON {

    var name:String?

    required init() {}// 如果定义是struct,连init()函数都不用声明;

}

 

***********

//第三层模型

import UIKit

import HandyJSON

class LYBthreemodel: HandyJSON {

    var age:String?

    required init() {}// 如果定义是struct,连init()函数都不用声明;

}

 

 

使用:

//1.这是一个JSON字符串,字符串内只有字典嵌套,指定路径解析        let jsonStr = "{\"name\": \"hangge\", \"age\": 100, \"phones\":{\"name\": {\"age\": 100}}}"        let model=JSONDeserializer
.deserializeFrom(json: jsonStr, designatedPath: "phones.name") print(model?.age)/1.这是一个JSON字符串,字符串内只有字典嵌套,指定路径解析 let jsonStr = "{\"name\": \"hangge\", \"age\": 100, \"phones\":{\"name\": {\"age\": 100}}}" let model=JSONDeserializer
.deserializeFrom(json: jsonStr, designatedPath: "phones.name") print(model?.age)

7.**********************指定路径解析(字典的value值有数组,路径最多只能到数组的键值这里)

//第一层模型import UIKitimport HandyJSONclass LYBHandyJsononeModel: HandyJSON {  var name:String?var age:String?  var phones:[LYBHandyJsonSecModel]? required init() {}// 如果定义是struct,连init()函数都不用声明;}

//第二层模型

import UIKit

import HandyJSON

class LYBHandyJsonSecModel: HandyJSON {

    var name:String?

    required init() {}// 如果定义是struct,连init()函数都不用声明;

}

//第三层模型

import UIKit

import HandyJSON

class LYBthreemodel: HandyJSON {

    var age:String?

    required init() {}// 如果定义是struct,连init()函数都不用声明;

}

 

 

 

//1.这是一个JSON字符串,字典的value值是数组,指定路径解析        let jsonStr = "{\"name\": \"hangge\", \"age\": 100, \"phones\":[{\"name\": {\"age\": 100}}]}"        let model=JSONDeserializer
.deserializeModelArrayFrom(json: jsonStr, designatedPath: "phones")//因为phones是数组(所以要使用deserializeModelArrayFrom()),数组中元素可能有多个,无法确定唯一路径,这里只能指定到phones print(model) //1.这是一个JSON字符串,字典的value值是数组,指定路径解析 let jsonStr = "{\"name\": \"hangge\", \"age\": 100, \"phones\":[{\"name\": {\"age\": 100}}]}" let model=JSONDeserializer
.deserializeModelArrayFrom(json: jsonStr, designatedPath: "phones")//因为phones是数组(所以要使用deserializeModelArrayFrom()),数组中元素可能有多个,无法确定唯一路径,这里只能指定到phones print(model)

8.****************自定义解析方式*****************

 

 

HandyJSON还提供了一个扩展能力,就是允许自行定义Model类某个字段的解析Key、解析方式。我们经常会有这样的需求:

  • 某个Model中,我们不想使用和服务端约定的key作为属性名,想自己定一个;
  • 有些类型如enumtuple是无法直接从JSON中解析出来的,但我们在Model类中有这样的属性;

HandyJSON协议提供了一个可选的mapping()函数,我们可以在其中指定某个字段用什么Key、或者用什么方法从JSON中解析出它的值

//第一层模型

import UIKit

import HandyJSON

class LYBHandyJsononeModel: HandyJSON {

  var myname:String?

var age:(String,String)?

  var phones:[LYBHandyJsonSecModel]?

 required init() {}// 如果定义是struct,连init()函数都不用声明;

    

    func mapping(mapper: HelpingMapper) {

        //指定name字段用myname去解析

       mapper.specify(property: &myname, name: "name")

        //指定age用这个方法解析返回的是元祖,age中是100/200---分成100和200组成元组

        mapper.specify(property: &age) { (rawString) -> (String, String) in

            let parentNames = rawString.split(separator: "/").map(String.init)//

            return (parentNames[0], parentNames[1])

        }

       

       

 

    }

    

}

 

//第二层模型

import UIKit

import HandyJSON

class LYBHandyJsonSecModel: HandyJSON {

    var name:String?

    required init() {}// 如果定义是struct,连init()函数都不用声明;

}

 

 

//1.这是一个JSON字符串,解析的时候把100/200解析成一个元祖(100,200)    let jsonStr = "{\"name\": \"hangge\", \"age\":\"100/200\", \"phones\":[{\"name\": {\"age\": 100}}]}"        let model=JSONDeserializer
.deserializeFrom(json: jsonStr, designatedPath: "")//路径是空的话,意思和不带路径的方法一个效果 print(model?.age)解析的时候把100/200解析成一个元祖(100,200) let jsonStr = "{\"name\": \"hangge\", \"age\":\"100/200\", \"phones\":[{\"name\": {\"age\": 100}}]}" let model=JSONDeserializer
.deserializeFrom(json: jsonStr, designatedPath: "")//路径是空的话,意思和不带路径的方法一个效果 print(model?.age)

9.****************

 

你可能感兴趣的文章
base64 编码原理
查看>>
单链表是否有环的问题
查看>>
判断两个链表是否相交并找出交点
查看>>
归并排序
查看>>
STL常见问题
查看>>
time_wait和close_wait状态
查看>>
STL中vector、list、deque和map的区别
查看>>
Linux下多线程查看工具(pstree、ps、pstack)
查看>>
PID PPID LWP NLWP
查看>>
查看线程CPU占用情况
查看>>
查看个线程的CPU 内存占用
查看>>
Fiddler 教程
查看>>
apache 设置用户注意事项
查看>>
svn中设置文件夹链接
查看>>
find ./ -name "*.cgi" |xargs -i cp "{}" ./cgi-bin/
查看>>
svn st | awk '{if ( $1 == "?") { print $2}}' | xargs svn add
查看>>
mysql事务处理用法与实例详解
查看>>
利用iptables来配置linux禁止所有端口登陆和开放指定端口
查看>>
Python模块——struct
查看>>
mysql中select * for update
查看>>