runtime实战:JSON转实体-HBEntity

我们应该经常能碰到这样的场景:在网络数据回来之后需要将网络数据转化成实体(model),通常的做法是利用kvc来为实体赋值,或者利用现在已有的MJExtention、YYModel来做。

今天以我自己写的HBEntity为例解析下如何利用runtime来为实体赋值。


HBEntity简介:

HBEntity是一个利用runtime来将NSArray或NSDictionary对象转化成自定义实体的工具,支持多实体嵌套、免除了MJExtention和YYModel中白名单和黑名单的概念,同时还支持key与属性名之间的适配。

实现思路:

HBEntity实现将NSArray或NSDictionary对象转化成自定义实体的思路比较简单。我们把问题转换一下,上学的时候我们经常会遇到解y=f(x)的问题,现在把x与我们的NSArray和NSDictionary对象对应,y与我们自定义实体对应,f函数就是我们的HBEntity,我们来捋一下我们的已知条件,我们已知x和y,要求f! WTF,怎么解 。。 从x、y去推f,这个f可能有很多种啊!!我比较喜欢倒推。既然我们是要给自定义实体赋值,那我们需要知道这个实体有多少属性,每个属性是什么类型,有没有自定义getter 和setter方法等。runtime在这个时候就派上用场了。

在拿到实体所有的属性之后剩下的就是用NSDictionary或者NSArray对象(为了方便以下都简称为“对象”,我们自定义的类称为实体)赋值了。所以在这里我也不需要去过滤对象中哪些值是我不想参与赋值的(也就是blacklist),对于我来说没有blacklist和whitelist的区分。

总结起来为:

1.解析实体的属性

2.用对象的值为实体的属性赋值。

下面我们边看代码吧边bb吧。

1.解析实体的属性——runtime

解析实体的属性时我们会用到 class_copyPropertyList方法,

OBJC_EXPORT objc_property_t *class_copyPropertyList(Class cls, unsigned int *outCount)

__OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0);

该方法会将cls类里所有的属性都放到一个数组里返回,outCount返回的是属性的数量,如果该cls有父类,class_copyPropertyList方法并不会返回父类的属性,当然也不会将父类属性的个数计算到outCount内。这里需要说明的是objc_property_t是一个objc_property的结构体指针,objc_property有name 和 attributes,如果我们声明了一个属性

@property (nonatomic,copy,readonly)NSString *test;

这里test就是objc_property的name,可以通过property_getName来获取,而attributes可以通过property_getAttributes来获取,attributes是我们声明的属性(nonatomic,copy,readonly等)的描述,我们先来看下一个测试Demo返回的attribues,再来苹果文档里是怎么描述这一块的。

T@“NSString”,C,N,V_entityName这一串就是attributes

从上图可以看出,每个attribute都有name和value两部分组成,我们可以通过property_copyAttributeList来获得某个属性的atrributeList,每一项是objc_property_attribure_t类型,objc_property_attribure_t类型如下:

/// Defines a property attribute

typedef struct {

const char *name;          /**< The name of the attribute */

const char *value;          /**< The value of the attribute (usually empty) */

} objc_property_attribute_t;

那具体T、C、N这些符号代表的是什么意思呢?他的值又表示的是什么呢?我们求助一下官方文档。

上面是官方文档对T、C、N等做出的解答。下面再来看看他们的值代表的什么意思。

这里是官方文档的部分截图,可以看出我们可以通过T来知道该属性的类型。

官方文档里展示的例子并没有包含所有的类型,在我的HBEntity里有补充(下载地址:https://github.com/knighthb/HBEntity),感兴趣的同学可以下载下来看看。

基本上通过以上的几个方法就能确定一个类里有多少属性(不含父类的属性)、每个属性是详细信息等。

2.利用对象为实体赋值

这里基本上就是键值对映射,如果在适配器里为key和属性名做了适配,那么在赋值时将会把key对应的value赋值给对应的属性。

对于普通的类(属性里没有自定义类、没有数组等的类)这些工作已经足够了,对于比较棘手的我们就需要进行一下处理,比如对于属性是NSArray或NSMutableArray的类赋值时我们需要知道NSArray里装的是什么,也许有同学会说,这个简单,我们声明属性的时候声明为NSArray这样的形式就知道它是NSString的啦,乍一看是的,但是你用runtime根本拿不出来,因为这种写法是编译时的,只是告诉编译器array里装的是NSString,所以在runtime根本找不到。因此这块避免不了MJExtention或YYModel里指定类名的这类操作,如果有同学有好的解决方法请不吝赐教。

另外还有一个棘手的问题就是数值类型的处理,需要装箱拆箱过程,一直没有想出出去硬编码的方法,如果有同学解决过类似的问题也请不吝赐教。

最后上点Demo:

//HBTestPerson.h

#import "HBEntity.h"

#import "HBTestEntity.h"

@interface HBTestPerson : HBEntity

@property (nonatomic , copy)NSString * entityName;

@property (nonatomic , strong) NSString *entityNum;

@property (nonatomic , strong,setter=setEntityAge2:) HBTestEntity *testEntity;

@property (nonatomic , strong) NSMutableArray* testEntities;

@property (nonatomic , assign) BOOL boolTest;

@end

//HBTestPerson.m

#import "HBTestPerson.h"

@implementation HBTestPerson

- (NSDictionary *)hb_transferDic {

return @{@"entityname":@"entityName",

@"entitynum":@"entityNum"};

}

+ (NSDictionary *)hb_objectClassForKeyDic {

return @{@"testEntities":[HBTestEntity class]};

}

- (void)setEntityAge2:(HBTestEntity *)entityAge {

_testEntity = entityAge;

}

@end

//HBTestEntity.h

#import "HBEntity.h"

@interface HBTestEntity : HBEntity

@property (nonatomic , copy) NSString * name;

@property (nonatomic , copy) NSNumber * age;

@end

//HBTestEntity.m

#import "HBTestEntity.h"

@implementation HBTestEntity

- (void)setName:(NSString *)name {

_name = name;

}

@end

//HBArrayTestEntity.h

#import "HBEntity.h"

@interface HBArrayTestEntity : HBEntity

@property (nonatomic , strong) NSMutableArray * array;

@end

//HBArrayTestEntity.m

#import "HBArrayTestEntity.h"

#import "HBTestEntity.h"

@implementation HBArrayTestEntity

+ (NSDictionary *)hb_objectClassForKeyDic {

return @{@"array":[HBTestEntity class]};

}

@end

上面是几个测试类,下面是测试代码

NSDictionary * entityDic = @{@"entityname":@"hehe",

@"entitynum":@"1",

@"testEntity":@{@"name":@"xiaoming",

@"age":@(34)

},

@"testEntities":@[@{@"name":@"xiaoming",

@"age":@(34)

},

@{@"name":@"xiaoming",

@"age":@(34)

},

@{@"name":@"xiaoming",

@"age":@(34)

}]};

HBTestPerson * entity = [HBTestPerson transferEntityWithDic:entityDic];

NSArray * entityArray = @[@{@"name":@"xiaoming",

@"age":@(34)

},

@{@"name":@"xiaoming",

@"age":@(34)

},

@{@"name":@"xiaoming",

@"age":@(34)

}];

HBArrayTestEntity * arrayTestEntity = [HBArrayTestEntity transferEntityWithObject:entityArray];

结果如下:


总结:

不要脸的取了个总结,主要是为了贴下github的地址

github地址:https://github.com/knighthb/HBEntity

或者 git clone https://github.com/knighthb/HBEntity.git

也可以通过Pod 来安装 HBEntity玩耍

pod 'HBEntity'

希望通过解析HBEntity能让大家对runtime能有不一样的认识,如果大家在玩耍的过程中遇到了问题或者发现了bug请及时联系我

QQ:513179531

微信:knight_hb

或者在底下留言 ^ ^

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,098评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,213评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,960评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,519评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,512评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,533评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,914评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,574评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,804评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,563评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,644评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,350评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,933评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,908评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,146评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,847评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,361评论 2 342

推荐阅读更多精彩内容

  • 两天早上拿着笔没流出什么东西。 今天下班前开了个小会,把这两天做的东西总结了一番,接下来几天是项目比较具有挑战性的...
    大瑞RayD阅读 513评论 1 3
  • 今天是平安夜,一个充满寓意与无限美好的日子。 走到校园外,天空刚好下起了微微雨,武汉的冬天就是这样,存在于微风、寒...
    闻香识妞阅读 488评论 7 6
  • —————1.初始化( key一定要是可以hash的(String, Int, Float, Double, Bo...
    Jason_Wong阅读 6,836评论 0 4
  • 你想知道我对你的爱情是什么吗?就是从心底里喜欢你,觉得你的一举一动都很亲切,不高兴你比喜欢我更喜欢别人。你要是喜欢...
    一念归远阅读 59评论 0 0