1 字典key与模型属性不匹配(模型属性数量>字典键值对数)
#import "NSObject+Model.h"
#import <objc/message.h>
@implementation NSObject (Model)//获取类中的所有成员变量
//class_copyIvarList(__unsafe_unretained Class cls, unsigned int *outCount)
// Runtime:根据模型中属性,去字典中取出对应的value给模型属性赋值
// 思路:遍历模型中所有属性->使用运行时
+ (instancetype)modelWithDict:(NSDictionary *)dict
{
// 1.创建对应的对象
id objc = [[self alloc] init];
// 2.利用runtime给对象中的属性赋值
/**
class_copyIvarList: 获取类中的所有成员变量
Ivar:成员变量,以下划线开头
第一个参数:表示获取哪个类中的成员变量
第二个参数:表示这个类有多少成员变量,传入一个Int变量地址,会自动给这个变量赋值
返回值Ivar *:指的是一个ivar数组,会把所有成员属性放在一个数组中,通过返回的数组就能全部获取到。
count: 成员变量个数
*/
unsigned int count = 0;
// 获取类中的所有成员变量
Ivar *ivarList = class_copyIvarList(self, &count);
// 遍历所有成员变量
for (int i = 0; i < count; i++) {
// 根据角标,从数组取出对应的成员变量
Ivar ivar = ivarList[i];
// 获取成员变量名字
NSString *ivarName = [NSString stringWithUTF8String:ivar_getName(ivar)];
// 处理成员变量名->字典中的key(去掉 _ ,从第一个角标开始截取)
NSString *key = [ivarName substringFromIndex:1];
// 根据成员属性名去字典中查找对应的value
id value = dict[key];
//【如果模型属性数量大于字典键值对数理,模型属性会被赋值为nil】
// 而报错 (could not set nil as the value for the key age.)
if (value) {
// 给模型中属性赋值
[objc setValue:value forKey:key];
}
}
return objc;
}
@end
2 模型中嵌套模型(模型属性是另外一个模型对象)
#import "NSObject+Mod.h"
#import <objc/message.h>
@implementation NSObject (Mod)
// 获取类里面所有方法
// class_copyMethodList(__unsafe_unretained Class cls, unsigned int *outCount)// 本质:创建谁的对象
// 获取类里面属性
// class_copyPropertyList(<#__unsafe_unretained Class cls#>, <#unsigned int *outCount#>)
// Ivar:成员变量 以下划线开头
// Property:属性
+ (instancetype)modelWithDict2:(NSDictionary *)dict
{
// 1.创建对应的对象
id objc = [[self alloc] init];
// 2.利用runtime给对象中的属性赋值
/**
class_copyIvarList: 获取类中的所有成员变量
Ivar:成员变量
第一个参数:表示获取哪个类中的成员变量
第二个参数:表示这个类有多少成成员变量,传入一个Int变量地址,会自动给这个变量赋值
返回值Ivar *:指的是一个ivar数组,会把所有成员属性放在一个数组中,通过返回的数组就能全部获取到。
count: 成员变量个数
*/
unsigned int count = 0;
// 获取类中的所有成员变量
Ivar *ivarList = class_copyIvarList(self, &count);
// 遍历所有成员变量
for (int i = 0; i < count; i++) {
// 根据角标,从数组取出对应的成员变量
Ivar ivar = ivarList[i];
// 获取成员变量名字
NSString *ivarName = [NSString stringWithUTF8String:ivar_getName(ivar)];
// 获取成员变量类型
NSString *ivarType = [NSString stringWithUTF8String:ivar_getTypeEncoding(ivar)];
// 替换: @\"NSString\" -> NSString
ivarType = [ivarType stringByReplacingOccurrencesOfString:@"\"" withString:@""];
ivarType = [ivarType stringByReplacingOccurrencesOfString:@"@" withString:@""];
// 处理成员变量名->字典中的key(去掉 _ ,从第一个角标开始截取)
NSString *key = [ivarName substringFromIndex:1];
// 根据成员属性名去字典中查找对应的value
id value = dict[key];
// 二级转换:如果字典中还有字典,也需要把对应的字典转换成模型
// 判断下value是否是字典,并且是自定义对象才需要转换
if ([value isKindOfClass:[NSDictionary class]] && ![ivarType hasPrefix:@"NS"]) {
// 字典转换成模型 userDict => User模型, 转换成哪个模型
// 根据字符串类名生成类对象
Class modelClass = NSClassFromString(ivarType);
if (modelClass) { // 有对应的模型才需要转
// 把字典转模型
value = [modelClass modelWithDict2:value];
}
}
// 给模型中属性赋值
if (value) {
[objc setValue:value forKey:key];
}
}
return objc;
}
@end
3 数组中装着模型(模型属性是数组,数组中是字典模型对象)
#import "NSObject+Item.h"
#import <objc/message.h>
@implementation NSObject (Item)
// Runtime:根据模型中属性,去字典中取出对应的value给模型属性赋值
// 思路:遍历模型中所有属性->使用运行时
+ (instancetype)modelWithDict3:(NSDictionary *)dict
{
// 1.创建对应的对象
id objc = [[self alloc] init];
// 2.利用runtime给对象中的属性赋值
/**
class_copyIvarList: 获取类中的所有成员变量
Ivar:成员变量
第一个参数:表示获取哪个类中的成员变量
第二个参数:表示这个类有多少成员变量,传入一个Int变量地址,会自动给这个变量赋值
返回值Ivar *:指的是一个ivar数组,会把所有成员属性放在一个数组中,通过返回的数组就能全部获取到。
count: 成员变量个数
*/
unsigned int count = 0;
// 获取类中的所有成员变量
Ivar *ivarList = class_copyIvarList(self, &count);
// 遍历所有成员变量
for (int i = 0; i < count; i++) {
// 根据角标,从数组取出对应的成员变量
Ivar ivar = ivarList[i];
// 获取成员变量名字
NSString *ivarName = [NSString stringWithUTF8String:ivar_getName(ivar)];
// 处理成员属性名->字典中的key(去掉 _ ,从第一个角标开始截取)
NSString *key = [ivarName substringFromIndex:1];
// 根据成员属性名去字典中查找对应的value
id value = dict[key];
//--------------------------- <#我是分割线#> ------------------------------//
//
// 三级转换:NSArray中也是字典,把数组中的字典转换成模型.
// 判断值是否是数组
if ([value isKindOfClass:[NSArray class]]) {
// 判断对应类有没有实现字典数组转模型数组的协议
// arrayContainModelClass 提供一个协议,只要遵守这个协议的类,都能把数组中的字典转模型
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 modelWithDict3:dict];
[arrM addObject:model];
}
// 把模型数组赋值给value
value = arrM;
}
}
// 如果模型属性数量大于字典键值对数理,模型属性会被赋值为nil,而报错
if (value) {
// 给模型中属性赋值
[objc setValue:value forKey:key];
}
}
return objc;
}
@end