1 动态添加属性
若想给系统的类添加属性,可以采用Runtime的方法,比如:
给系统的NSObject类添加一个name属性,过程如下:
1) 创建一个NSObject的分类,NSObject+Property
2)在NSObject+Property.h文件中声明属性
@property NSString *name;
备注: 在分类中是不能添加属性的,
常用@property方法在分类中只会生成get,set方法声明,并不会生成get,set方法实现和下划线成员变量,所以此处简写成@property NSString *name;声明一下即可。
3)在NSObject+Property.m文件中采用runtime方法实现
- (void)setName:(NSString *)name
{
// 第一个参数:给哪个对象产生关联
// 第二个参数:属性名
// 第三个参数:属性值
// 第四个参数:策略
objc_setAssociatedObject(self, "name", name, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (NSString *)name
{
return objc_getAssociatedObject(self, "name");
}
2 自动添加属性的方法
在将字典转成模型的过程中,如果字典中包含很多key,并且这些key都要转成相应的模型,此时手动在模型的.h文件中添加property属性,也是一项繁琐的工作,下面是如何快速生成属性列表的方法:
1)新建一个NSDictionary的分类
2)提供一个方法,在该方法中实现代码:
- (void)PropertyCode
{
// 生成多少个属性代码 => 字典key
// 创建可变字符串
NSMutableString *codes = [NSMutableString string];
// 私有API:苹果没有暴露出来的类
// 遍历字典
[self enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull value, BOOL * _Nonnull stop) {
NSString *code ;
if ([value isKindOfClass:[NSString class]]) {
// NSString
code = [NSString stringWithFormat:@"@property (nonatomic, strong) NSString *%@;",key];
} else if ([value isKindOfClass:[NSArray class]]) {
// NSArray
code = [NSString stringWithFormat:@"@property (nonatomic, strong) NSArray *%@;",key];
} else if ([value isKindOfClass:[NSDictionary class]]) {
// NSDictionary
code = [NSString stringWithFormat:@"@property (nonatomic, strong) NSDictionary *%@;",key];
} else if ([value isKindOfClass:NSClassFromString(@"__NSCFBoolean")]) {
code = [NSString stringWithFormat:@"@property (nonatomic, assign) BOOL %@;",key];
} else if ([value isKindOfClass:[NSNumber class]]) {
code = [NSString stringWithFormat:@"@property (nonatomic, assign) NSInteger %@;",key];
}
[codes appendFormat:@"\n%@\n",code];
}];
NSLog(@"%@",codes);
}
- 获取属性列表
在获取字典的地方调用[dict PropertyCode];即可 NSLog(@"%@",codes);codes就是属性列表,直接拷贝到模型的.h文件中即可。
3 字典转模型
3.1 KVC的方法
// 1.创建模型对象
Status *status = [[self alloc] init];
// 2.调用KVC方法:setValuesForKeysWithDictionary
[status setValuesForKeysWithDictionary:dict];
缺点:必须要保证模型的属性跟字典的key一一对应,否则会崩溃
setValuesForKeysWithDictionary底层的实现原理:
// 1.快速遍历字典
[dict enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull obj, BOOL * _Nonnull stop) {
NSLog(@"%@ %@",key,obj);
// 2.去模型中查找有没有key对应的set方法,如果有,直接调用方法赋值,
// 3.没有set方法,就去模型中查找有没有key对应的成员变量,如果有,直接给key赋值
// 4.没有key对应的成员变量,就去模型中查找有没有_key,有,直接给_key赋值
// 5. 2,3,4 都没有时就调用- (void)setValue:(id)value forUndefinedKey:(NSString *)key方法,查不到的错误
备注:如果不想系统报错,可以重写- (void)setValue:(id)value forUndefinedKey:(NSString *)key{} (不推荐)
3.2 runtime的方法(不存在崩溃的问题)
1) 自定义一个NSObject的分类
2)提供一个方法
// 字典转模型
+ (instancetype)modelWithDict:(NSDictionary *)dict
{
// 1.创建模型对象
id objc = [[self alloc] init];
// 把字典中的value给模型中属性赋值
// runtime:1.遍历模型中成员变量,2.去字典中查找对应的value3.给模型中属性赋值
// ivar:成员变量
// 第一个参数:获取哪个类的成员变量
// 第二个参数:类中成员变量总数
unsigned int count;
// 获取成员变量数组:注意:只会获取当前类的属性,不会获取父类
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)];
// @\"User\"=> User
ivarType = [ivarType stringByReplacingOccurrencesOfString:@"\"" withString:@""];
ivarType = [ivarType stringByReplacingOccurrencesOfString:@"@" withString:@""];
// 获取key:user
NSString *key = [ivarName substringFromIndex:1];
// 获取字典的value:NSDictionary
id value = dict[key];
// 二级:如果是字典,转模型
if ([value isKindOfClass:[NSDictionary class]] && ![ivarType hasPrefix:@"NS"]) {
// 根据类名字符串转换成类对象
Class modelClass = NSClassFromString(ivarType);
// 字典转模型
value = [modelClass modelWithDict:value];
}
// 给模型中属性赋值
[objc setValue:value forKey:key];
}
return objc;
}
3)调用方法
// 字典转模型
Status *s = [Status modelWithDict:dict];
网友评论