iOS中字典转模型的方法及底层原理
来源:互联网 发布:linux more 到最后 编辑:程序博客网 时间:2024/05/21 19:22
1 自动打印属性字符串分类
- 提供一个分类,专门根据字典生成对应的属性字符串。
@implementation NSObject (Property)+ (void)PH_createPropertyCodeWithDict:(NSDictionary *)dict{ NSMutableString *strM = [NSMutableString string]; // 遍历字典 [dict enumerateKeysAndObjectsUsingBlock:^(id _Nonnull propertyName, id _Nonnull value, BOOL * _Nonnull stop) { NSLog(@"%@,%@",propertyName,[value class]); NSString *code; if ([value isKindOfClass:NSClassFromString(@"__NSCFString")]) { code = [NSString stringWithFormat:@"@property (nonatomic, strong) NSString *%@;",propertyName] ; } else if ([value isKindOfClass:NSClassFromString(@"__NSCFNumber")]){ code = [NSString stringWithFormat:@"@property (nonatomic, assign) int %@;",propertyName] ; }else if ([value isKindOfClass:NSClassFromString(@"__NSCFArray")]){ code = [NSString stringWithFormat:@"@property (nonatomic, strong) NSArray *%@;",propertyName] ; }else if ([value isKindOfClass:NSClassFromString(@"__NSCFDictionary")]){ code = [NSString stringWithFormat:@"@property (nonatomic, strong) NSDictionary *%@;",propertyName] ; } else if ([value isKindOfClass:NSClassFromString(@"__NSCFBoolean")]){ code = [NSString stringWithFormat:@"@property (nonatomic, assign) BOOL %@;",propertyName] ; } [strM appendFormat:@"\n%@\n",code]; }]; NSLog(@"%@",strM);}@end
2 字典转模型的方式一:KVC
@implementation Status+ (instancetype)statusWithDict:(NSDictionary *)dict{ Status *status = [[self alloc] init]; [status setValuesForKeysWithDictionary:dict]; return status;}@end
- KVC字典转模型弊端:必须保证,模型中的属性和字典中的key一一对应。
- 如果不一致,就会调用
[<Status 0x7fa74b545d60> setValue:forUndefinedKey:]
报key
找不到的错。 - 分析:模型中的属性和字典的key不一一对应,系统就会调用
setValue:forUndefinedKey:
报错。 - 解决:重写对象的
setValue:forUndefinedKey:
,把系统的方法覆盖,
就能继续使用KVC,字典转模型了。
- 如果不一致,就会调用
- (void)setValue:(id)value forUndefinedKey:(NSString *)key{}
3 字典转模型的方式二:Runtime
- KVC:遍历字典中所有key,去模型中查找有没有对应的属性名
- runtime:遍历模型中所有属性名,去字典中查找
1.思路与步骤
<!--* 思路:利用运行时,遍历模型中所有属性,根据模型的属性名,去字典中查找key,取出对应的值,给模型的属性赋值。--><!--* 步骤:提供一个NSObject分类,专门字典转模型,以后所有模型都可以通过这个分类转。-->
2.分类
+ (instancetype)PH_modelWithDict:(NSDictionary *)dict{ // 创建对应类的对象 id objc = [[self alloc] init]; // runtime:遍历模型中所有成员属性,去字典中查找 // 属性定义在哪,定义在类,类里面有个属性列表(数组) // 遍历模型所有成员属性 // ivar:成员属性 // class_copyIvarList:把成员属性列表复制一份给你 // Ivar *:指向Ivar指针 // Ivar *:指向一个成员变量数组 // class:获取哪个类的成员属性列表 // count:成员属性总数 unsigned int count = 0; Ivar *ivarList = class_copyIvarList(self, &count); for (int i = 0; i < count; i++) { // 获取成员属性 Ivar ivar = ivarList[i]; // 获取成员名 NSString *propertyName = [NSString stringWithUTF8String:ivar_getName(ivar)]; //成员属性类型 NSString *propertyType = [NSString stringWithUTF8String:ivar_getTypeEncoding(ivar)]; //获取key NSString *key = [propertyName substringFromIndex:1]; //获取字典的value id value = dict[key]; // 给模型的属性赋值 // value:字典的值 // key:属性名// user:NSDictionary //** '二级转换'** // 值是字典,成员属性的类型不是字典,才需要转换成模型 if ([value isKindOfClass:[NSDictionary class]] && ![propertyType containsString:@"NS"]) { // 需要字典转换成模型 // 转换成哪个类型 // @"@\"User\"" User NSRange range = [propertyType rangeOfString:@"\""]; propertyType = [propertyType substringFromIndex:range.location + range.length]; // User\""; range = [propertyType rangeOfString:@"\""]; propertyType = [propertyType substringFromIndex:range.location]; // 字符串截取 // 获取需要转换类的类对象 Class modelClass = NSClassFromString(propertyType); if (modelClass) { value = [modelClass PH_modelWithDict:value]; } }<!-- 三级转换:NSArray中也是字典,把数组中的字典转换成模型.--> // 判断值是否是数组 if ([value isKindOfClass:[NSArray class]]) { //判断对应类有没有实现字典数组转模型数组的协议 if ([self respondsToSelector:@selector(PH_arrayContainModelClass)]) { // 转换成id类型,就能调用任何对象的方法 id idSelf = self; // 获取数组中字典对应的模型 NSString *type = [idSelf PH_arrayContainModelClass][key]; // 生成模型 Class classModel = NSClassFromString(type); NSMutableArray *arrM = [NSMutableArray array]; // 遍历字典数组,生成模型数组 for (NSDictionary *dict in value) { // 字典转模型 id model = [classModel PH_modelWithDict:dict]; [arrM addObject:model]; } // 把模型数组赋值给value value = arrM; } } if (value) { // kvc赋值:不能传空 [objc setValue:value forKey:key]; } NSLog(@"%@",key); NSLog(@"%@,%@",propertyName,propertyType); } return objc;}
3.转换
- (void)viewDidLoad { [super viewDidLoad]; // 解析 NSString *filePath = [[NSBundle mainBundle] pathForResource:@"status.plist" ofType:nil]; NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:filePath]; NSArray *dictArr = dict[@"statuses"]; // 设计模型属性代码 NSMutableArray *statuses = [NSMutableArray array]; for (NSDictionary *dict in dictArr) { // 字典转模型 Status *status = [Status PH_modelWithDict:dict]; [statuses addObject:status]; } NSLog(@"%@",statuses);
}
KVC: Key Value Coding (键值编码)
在iOS开发中,KVC是我们经常要使用的技术.那么KVC有什么作用呢?简单列举一下下面几种:
- 取值和赋值(开发中基本不用)
- 获取对象私有变量的值.(经常使用,例如UIPageContorl分页, 设置圆点为图片)
- 改变对象私有变量的值(经常使用)
- 简单的字典转模型(偶尔使用)
- 模型转字典
- 批量取值
KVC字典转模型的底层实现
通常我们手动将字典转模型的话,会在模型中提供一个类方法接收一个字典,在这个方法中将字典转换成模型,再将转换好的模型返回.
+ (instancetype)statusWithDict:(NSDictionary *)dict{ Status *status = [[self alloc] init]; //利用KVC字典转模型 [status setValuesForKeysWithDictionary:dict]; return status;}
分析一下
[status setValuesForKeysWithDictionary:dict]
的底层实现原理+ (instancetype)statusWithDict:(NSDictionary *)dict{ Status *status = [[self alloc] init]; //利用KVC字典转模型 //[status setValuesForKeysWithDictionary:dict]; //setValuesForKeysWithDictionary:原理--遍历字典中所有的key,去模型中查找对应的属性,把值给模型属性赋值 [dict enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull obj, BOOL * _Nonnull stop) { // 这行代码才是真正给模型的属性赋值 [status setValue:obj forKey:key]; }]; return status;}
- KVC字典转模型弊端:必须保证,模型中的属性和字典中的key一一对应。如果不是一一对应的话,就会报错,仔细看一下错误信息,
[<Status 0x7fd439d20a60> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key source.
是系统调用了setValue:forUndefinedKey:报错.如果想解决这个问题,只需要在模型中重写对象的setValue:forUndefinedKey:,把系统的方法覆盖, 就能继续使用KVC,字典转模型了。- (void)setValue:(id)value forUndefinedKey:(NSString *)key{}
啰嗦一点KVC的setValue:forKey:
方法赋值的原理
- 首先会去模型中查找有没有对应key的setter方法,有就直接调用set方法方法赋值.
- 上一步没有的话,去模型中查找有没有和key同名的属性,有的话赋值给与key同名的属性.
- 上一步还没有的话,去属性中查找有没有和key同名的带下划线的属性,有的话直接赋值.
- 如果再没有,那就直接调用对象的 setValue:forUndefinedKey:直接报错
阅读全文
0 0
- iOS中字典转模型的方法及底层原理
- MCV中字典转模型的KVC底层实现
- iOS 字典转模型~方法
- 字典转模型的几中方法
- iOS中KVO的底层实现原理
- iOS字典转模型方法代理片段
- 字典转模型的方法
- IOS字典转模型
- ios 字典转模型
- iOS 字典转模型
- iOS 字典转模型
- iOS 字典转模型
- ios-字典转模型
- iOS越狱的底层原理
- iOS中__block 关键字的底层实现原理
- iOS中__block 关键字的底层实现原理
- C++中虚继承的作用及底层实现原理
- iOS-字典转模型(单模型)的实现
- java学习笔记(三十五)JDBC
- layer Cannot read property 'extend' of undefined
- 面试题16. 反转链表
- mysql 服务器配置
- InnoDB Adaptive Hash Index浅析
- iOS中字典转模型的方法及底层原理
- 关于三维模型网格分块的一点小技巧(不定时更新))
- Linux 搜索命令(locate/find/whereis/which/grep)
- Windows下装memcacahe
- MyBatis笔记——基本配置与访问
- BZOJ 1875 [SDOI2009]HH去散步 (矩阵快速幂)
- pxe
- Android中单选框选中改变图片的示例
- Kafka学习笔记——Kafka简介与使用场景介绍