本文共 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
出现以前,主要使用两种方式:
让Model类继承自NSObject
,然后class_copyPropertyList()
方法获取属性名作为Key,从JSON中取得Value,再通过Objective-C runtime
支持的KVC
机制为类属性赋值;如JSONNeverDie
;
支持纯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类也实现了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类实现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=JSONDeserializer7.**********************指定路径解析(字典的value值有数组,路径最多只能到数组的键值这里).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)
//第一层模型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=JSONDeserializer8.****************自定义解析方式*****************.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)
HandyJSON
还提供了一个扩展能力,就是允许自行定义Model类某个字段的解析Key、解析方式。我们经常会有这样的需求:
enum
、tuple
是无法直接从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=JSONDeserializer9.****************.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)