美文网首页RumeTime程序员iOS 开发
runtime实战:JSON转实体-HBEntity

runtime实战:JSON转实体-HBEntity

作者: knighthb | 来源:发表于2016-04-08 12:59 被阅读430次

    我们应该经常能碰到这样的场景:在网络数据回来之后需要将网络数据转化成实体(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

    或者在底下留言 ^ ^

    相关文章

      网友评论

      本文标题:runtime实战:JSON转实体-HBEntity

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