@implementation NSObject (Property)
+ ( void )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]
;
}elseif ([value isKindOfClass:NSClassFromString(@"__NSCFArray")]){
code = [NSString stringWithFormat:@"@property (nonatomic, strong) NSArray *%@;",propertyName]
;
}elseif ([value isKindOfClass:NSClassFromString(@"__NSCFDictionary")]){
code = [NSString stringWithFormat:@"@property (nonatomic, strong) NSDictionary *%@;",propertyName]
;
}elseif ([value isKindOfClass:NSClassFromString(@"__NSCFBoolean")]){
code = [NSString stringWithFormat:@"@property (nonatomic, assign) BOOL %@;",propertyName]
;
}
[strM appendFormat:@"\n%@\n",code];
NSLog( @"%@" ,strM);
+ ( Status *)statusWithDict:( NSDictionary *)dict
{
Status *status = [[ self alloc] init];
// KVC
[status setValuesForKeysWithDictionary:dict];
return status;
}
-
- 如果不一致,就会调用
[<Status 0x7fa74b545d60> setValue:forUndefinedKey:]
报key
找不到的错。 - 分析:模型中的属性和字典的key不一一对应,系统就会调用
setValue:forUndefinedKey:
报错。 - 解决:重写对象的
setValue:forUndefinedKey:
,把系统的方法覆盖, 就能继续使用KVC,字典转模型了。
- 如果不一致,就会调用
- ( void )setValue:( id )value forUndefinedKey:( NSString *)key
{
if ([key isEqualToString: @"id" ]) {
_ID = [value integerValue];
}
// key: 没有找到 key
// value: 没有找到 key 对应的值
NSLog( @"%@ %@" ,key,value);
}
- 思路:利用运行时,遍历模型中所有属性,根据模型的属性名,去字典中查找key,取出对应的值,给模型的属性赋值。
- 步骤:提供一个NSObject分类,专门字典转模型,以后所有模型都可以通过这个分类转。
// 创建对应类的对象
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:属性名
// 值是字典 , 成员属性的类型不是字典 , 才需要转换成模型
if ([value isKindOfClass:[ NSDictionary class]] && ![propertyType containsString: @"NS" ]) { // 需要字典转换成模型
// 转换成哪个类型
propertyType = [propertyType substringFromIndex:range.location + range.length];
// User\"";
range = [propertyType rangeOfString: @"\"" ];
propertyType = [propertyType substringToIndex:range.location];
// 字符串截取
// 获取需要转换类的类对象
Class modelClass = NSClassFromString(propertyType);
if (modelClass) {
value = [modelClass modelWithDict :value];
}
if (value) {
// KVC赋值:不能传空
[objc setValue:value forKey:key];
}
// NSLog(@"%@",key);
// NSLog(@"%@ %@",propertyType , propertyName);
}
return objc;
// 三级转换:NSArray中也是字典,把数组中的字典转换成模型.
// 判断值是否是数组
if ([value isKindOfClass:[NSArray class]]) {
// 判断对应类有没有实现字典数组转模型数组的协议
if ([self respondsToSelector:@selector(arrayContainModelClass)]) {
// 转换成id类型,就能调用任何对象的方法
id idSelf = self;
// 获取数组中字典对应的模型
NSString *type = [idSelf arrayContainModelClass][key];
// 生成模型
Class classModel = NSClassFromString(type);
NSMutableArray *arrM = [NSMutableArray array];
// 遍历字典数组,生成模型数组
for (NSDictionary *dict in value) {
// 字典转模型
id model = [classModel modelWithDict:dict];
[arrM addObject:model];
}
// 把模型数组赋值给value
value = arrM;
}
}
// 值是字典 , 成员属性的类型不是字典 , 才需要转换成模型
if ([value isKindOfClass:[ NSDictionary class]] && ![propertyType containsString: @"NS" ]) { // 需要字典转换成模型
// 转换成哪个类型
propertyType = [propertyType substringFromIndex:range.location + range.length];
// User\"";
range = [propertyType rangeOfString: @"\"" ];
propertyType = [propertyType substringToIndex:range.location];
// 字符串截取
// 获取需要转换类的类对象
Class modelClass = NSClassFromString(propertyType);
if (modelClass) {
value = [modelClass modelWithDict :value];
}