参考swift4.0字典转模型:https://www.cnblogs.com/shaoting/p/8087153.html
=====================kvc字典转模型=========================
*****第一层模型
import UIKit
class 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 UIKit
class 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 <Foundation/Foundation.h>
#import <MJExtension/MJExtension.h>
@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 <Foundation/Foundation.h>
#import <MJExtension/MJExtension.h>
@interface LYBmjextentionModelTosec : NSObject
@property(nonatomic,copy)NSString *name;
@property(nonatomic,copy)NSString *number;
@end
************************
#import "LYBmjextentionModelTosec.h"
@implementation LYBmjextentionModelTosec
@end
**************************
swift的桥接文件中
#import <MJExtension/MJExtension.h>
#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 UIKit
import HandyJSON
class 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<LYBHandyJsononeModel>.deserializeFrom(dict: dict)
print((model?.name)!)
}
}
catch {
}
3.***************---json字符串中的最外层是数组;
import UIKit
import HandyJSON
class 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<LYBHandyJsononeModel>.deserializeModelArrayFrom(json: jsonStr)
print((model?[0]?.age)!)
4.***********json字符串,最外层是数组,数组中的内容是字典
import UIKit
import HandyJSON
class 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<LYBHandyJsononeModel>.deserializeModelArrayFrom(array: dictArr)
print((model![0]?.name)!)
}
}
catch {
}
let model=JSONDeserializer<LYBHandyJsononeModel>.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<LYBHomeHeaderScrollModel>.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 UIKit
class LYBTabAndCollectionConnectModel: HandyJSON {
var leftone:[LYBrightSecModel]?
var lefttwo:[LYBrightSecModel]?
var leftthree:[LYBrightSecModel]?
required init(){
}
}
*******第二层
import UIKit
class 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 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?
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<LYBHandyJsononeModel>.deserializeModelArrayFrom(array: dictArr)
let phones=model![0]?.phones;
print("\((phones![1].name)!)")
}
}
catch {
}
let model=JSONDeserializer<LYBHandyJsononeModel>.deserializeModelArrayFrom(array: dictArr)
let phones=model![0]?.phones;
print("\((phones![1].name)!)")
}
}
catch {
}
6.********************指定反序列化JSON中某个节点(指定路径转模型,可以选择有用的数组转模型,跳过无用的数据)------解析的指定路径要保证唯一性才可以;
<span style="color:#ff0000">这是一个JSON字符串,字符串内只有字典嵌套,可以任意指定路径解析</span>
有时候服务端返回给我们的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<LYBHandyJsononeModel>.deserializeFrom(json: jsonStr, designatedPath: "phones.name")
print(model?.age)
/1.这是一个JSON字符串,字符串内只有字典嵌套,指定路径解析
let jsonStr = "{\"name\": \"hangge\", \"age\": 100, \"phones\":{\"name\": {\"age\": 100}}}"
let model=JSONDeserializer<LYBHandyJsononeModel>.deserializeFrom(json: jsonStr, designatedPath: "phones.name")
print(model?.age)
7.**********************指定路径解析(字典的value值有数组,路径最多只能到数组的键值这里)
//第一层模型
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字符串,字典的value值是数组,指定路径解析
let jsonStr = "{\"name\": \"hangge\", \"age\": 100, \"phones\":[{\"name\": {\"age\": 100}}]}"
let model=JSONDeserializer<LYBHandyJsononeModel>.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<LYBHandyJsononeModel>.deserializeModelArrayFrom(json: jsonStr, designatedPath: "phones")//因为phones是数组(所以要使用deserializeModelArrayFrom()
),数组中元素可能有多个,无法确定唯一路径,这里只能指定到phones
print(model)
8.****************自定义解析方式*****************
HandyJSON
还提供了一个扩展能力,就是允许自行定义Model类某个字段的解析Key、解析方式。我们经常会有这样的需求:
- 某个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=JSONDeserializer<LYBHandyJsononeModel>.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<LYBHandyJsononeModel>.deserializeFrom(json: jsonStr, designatedPath: "")//路径是空的话,意思和不带路径的方法一个效果
print(model?.age)
9.****************