OC - Runtime&KVC知识回顾以及应用场景
KVC底层原理
遍历字典,一一赋值
-(instancetype)initWithDict:(NSDictionary * )dict{
MyModel *item = [[MyModel alloc]init];
[self enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull value, BOOL *
[item setValue:value forKey:key];
}];
return item;
}
例如:name
- 1.先找setName方法
- 2.找不到setName方法就找name属性
- 3.找不到name属性就找_name属性
- 4.如果都找不到,就报错
Runtime
方法使用场景和注意要点
-
交换方法
+(void)load{
Method imageNameMethod = class_getClassMethod(self, @selector(imageNamed:));
Method my_imageNameMethod = class_getClassMethod(self, @selector(my_ImageNamed:));
method_exchangeImplementations(imageNameMethod, my_imageNameMethod);
}
+(UIImage *)my_ImageNamed:(NSString *)Name{
UIImage * image = [UIImage my_ImageNamed:Name];
if (image) {
NSLog(@"加载成功");
}else{
NSLog(@"加载失败");
}
return image;
}
应用场景:希望扩充系统分类方法的时候。不改变原有系统方法的同时,实现自定义扩展方法。
要点:将交换实现写在 load
方法中,在加载程序的时候就会调用
-
动态添加属性
.h文件
@property NSString * name;//只是申明set,和get方法,并不实现
.m文件
-(void)setName:(NSString *)name{
/*
*objc_setAssociatedObject(id _Nonnull object, const void * _Nonnull key, id _Nullable value, objc_AssociationPolicy policy)
*object:哪个类
*key:属性名
*name:参数
*policy:策略
*/
objc_setAssociatedObject(self, "name", name, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
-(NSString *)name{
return objc_getAssociatedObject(self, "name");
}
应用场景:分类添加属性
-
动态添加方法(消息转发)
void doit(id self,SEL _cmd){//self和_cmd隐式参数,必须要
NSLog(@"进来了");
}
+(BOOL)resolveInstanceMethod:(SEL)sel{
if (sel == NSSelectorFromString(@"eat")) {
class_addMethod(self, sel, (IMP)doit, "v@:");
return YES;
}
return [super resolveInstanceMethod:sel];
}
应用场景:没必要一次性实现,付费用户功能等
要点:调用一个不存在的方法,如果找不到,会转发消息到resolveInstanceMethod方法,在resolveInstanceMethod中处理。