前言
有很多优秀的第三方框架实现序列化和反序列化的功能。我们可以通过集成这些框架,便捷的实现字典与模型之间的相互转换。例如MJExtension,YYModel。思考一下如何利用runtime的思想去便捷的实现模型和字典的相互转化。
思考
通常字典和模型的key需要一一对应,一个个的赋值模型属性是一个很繁琐的事情,可以不可以自动根据一个字典,自动赋值到对应的属性上。
如果直接简单的使用KVC赋值的方式虽然一句代码就可以搞定。
[person setValuesForKeysWithDictionary:dict];
但是这样的弊端是在太明显,如果模型中的属性和字典的key不是一一对应的,就会出现崩溃,setValue:forUndefinedKey:的情况。网络请求中常会出现数据和model属性不一致的情况,当字典的key包含model所有的属性,多一些model中不存在属性,不会出现问题。但是当model中的某个属性在字典中是不存在的key,则会崩溃。
利用runtime进行转换
我们可以通过runtime,去获取model这个类的属性列表,通过属性的名字,在字典中寻找到对应的值,进行KVC的赋值。这样既安全又便捷。同理,我们也可以通过遍历类的属性列表,将属性名作为key,属性值作为value,包装成一个字典。
下面代码简单实现的这样的思路。但并不严谨,因为考虑到数据类型和多层嵌套,关键字定义等等很多情况,需要做更严谨的处理。这里我们只是探究这样的思想,保证key-value一一对应,快速转换。
NSDictionary *dic = @{
@"name":@"Tom",
@"nick":@"cuzz",
@"age":@"22"
};
Person *p = [[Person alloc]initWithDict:dic];
NSLog(@"%@-----%@",p.name,p.nick);
NSDictionary *dict = [p convertModelToDict];
NSLog(@"%@",dict);
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface Person : NSObject
- (instancetype)initWithDict:(NSDictionary *)dict;
- (NSDictionary *)convertModelToDict;
@property (nonatomic, copy) NSString *name;
@property (nonatomic, copy) NSString *nick;
@end
NS_ASSUME_NONNULL_END
#import "Person.h"
#import <objc/message.h>
#import <objc/runtime.h>
@implementation Person
//key-value
//消息发送
// set 方法
//函数指针的格式 (*函数名)(param1,param2)
- (instancetype)initWithDict:(NSDictionary *)dict
{
self = [super init];
if (self) {
unsigned int count = 0;
objc_property_t *properties = class_copyPropertyList([self class], &count);
for (int i = 0; i<count; i++) {
const void *propertyName = property_getName(properties[i]);
NSString *name = [NSString stringWithUTF8String:propertyName];
[self setValue:dict[name] forKey:name];
}
free(properties);
}
return self;
}
//key - value
//key:class_copyPropertyList()
//value:get方法(objc_sendmsg)
- (NSDictionary *)convertModelToDict
{
unsigned int count = 0;
objc_property_t *properties = class_copyPropertyList([self class], &count);
NSMutableDictionary *tempDic = [NSMutableDictionary dictionary];
for (int i = 0; i<count; i++) {
objc_property_t property = properties[i];
const void *propertyName = property_getName(property);
NSString *name = [NSString stringWithUTF8String:propertyName];
SEL sel = NSSelectorFromString(name);
if (sel) {
id value = ((id(*)(id,SEL))objc_msgSend)(self,sel);
if (value) {
tempDic[name] = value;
}else {
tempDic[name] = @"";
}
}
}
free(properties);
return tempDic;
}
@end
网友评论