1.什么是Runtime
Runtime是Object-C中的一个库,主要用C和汇编写的,OC编写的代码最终都会转换为Runtime的C代码,用于消息的转发和传递
2.Runtime的基本用法
2.1 常用方法介绍
2.1.1 class_getClassMethod 获取某个类的方法
Method personMethod = class_getClassMethod([Class class], oriSEL);
2.1.2 class_getInstanceMethod 获取某个类的实例方法
Method changeMethod1 = class_getInstanceMethod([self class], @selector(changeFunc1));
Method changeMethod2 = class_getInstanceMethod([self class], @selector(changeFunc2));
-(void)changeFunc1{
NSLog(@"========== fuction1 ");
}
-(void)changeFunc2{
NSLog(@"========== fuction2 ");
}
2.1.3 method_exchangeImplementations 交换两个方法
method_exchangeImplementations(changeMethod2, changeMethod1);
2.1.4 class_addMethod 添加方法
我们先定义个Class 叫PersonClass
第一个参数是添加对象类
第二个参数是添加的方法
第三个参数是添加方法的IMP 用class_getMethodImplementation来获取
第四个参数是 传入方法是什么返回,是否带参 "v@:"等同于返回为void 不带参数
PersonClass *person = [[PersonClass alloc]init];
BOOL isAddSuccess = class_addMethod([person class], @selector(addClass), class_getMethodImplementation([self class], @selector(addClass)), "v@:");
if(isAddSuccess){
[person performSelector:@selector(addClass)];
}
2.1.4 class_replaceMethod替换方法
第一个参数是替换对象类
第二个参数是替换的方法
第三个参数是替换方法的IMP 用class_getMethodImplementation来获取
第四个参数是 传入方法是什么返回,是否带参 "v@:"等同于返回为void 不带参数
PersonClass *person = [[PersonClass alloc]init];
BOOL replaceMethod = class_replaceMethod([person class], @selector(getName), class_getMethodImplementation([self class],@selector(changeClass)),"v@:");
if(replaceMethod){
[person performSelector:@selector(getName) withObject:nil];
}
2.1.5 objc_setAssociatedObject objc_getAssociatedObject属性关联
OBJC_EXPORT void
objc_setAssociatedObject
(
id _Nonnull object,//被关联对象
const void * _Nonnull key,//关联的key
id _Nullable value,//关联的值,属性名
objc_AssociationPolicy policy//策略一般使用OBJC_ASSOCIATION_RETAIN_NONATOMIC
)
static char *overviewKey;
NSArray *array = [NSArray arrayWithObjects:@"a",@"b",@"c",nil];
NSString *arrayDesc = @"this is arrayDesc";
//关联
objc_setAssociatedObject(array, &overviewKey, arrayDesc, OBJC_ASSOCIATION_RETAIN);
NSString *associatedDesc = (NSString *)objc_getAssociatedObject(array, &overviewKey); NSLog(@"associatedDesc:%@", associatedDesc);
//取消关联
objc_setAssociatedObject(array, &overviewKey, nil, OBJC_ASSOCIATION_RETAIN);
NSString *associatedDesc2 = (NSString *)objc_getAssociatedObject(array, &overviewKey);
NSLog(@"associatedDesc2:%@", associatedDesc2);
2.1.6获取类属性
PersonClass *person = [[PersonClass alloc]init];
unsigned int count;
//获取类属性列表
objc_property_t *propertyList = class_copyPropertyList([person class], &count);
for(int i=0;i<count;i++){
objc_property_t property = propertyList[i];
NSLog(@"property name=%@",[NSString stringWithCString:property_getName(property) encoding:NSUTF8StringEncoding]);
}
free(propertyList);
//获取类方法列表
Method *methodList = class_copyMethodList([person class], &count);
for(int i=0;i<count;i++){
Method method = methodList[i];
NSString *str = NSStringFromSelector(method_getName(method));
NSLog(@"method name=%@",str);
}
free(methodList);
//获取成员变量
Ivar *ivarList = class_copyIvarList([person class], &count);
for(int i=0;i<count;i++){
Ivar ivar = ivarList[i];
NSString *str = [NSString stringWithUTF8String:ivar_getName(ivar)];
NSLog(@"ivar name=%@",str);
}
free(ivarList);
3 Runtime 消息转发
在runtime 中 我们用objc_msgSend来传递消息,但是在父类和子类都找不到对应的方法时,runtime会执行如下机制
了解消息转发的原理,我们可以在forwardingTargetForSelector进行捕获 避免Unrecognized Selector的错误
+(BOOL)resolveClassMethod:(SEL)sel{
if (sel == @selector(messageTest)) {
NSLog(@"1======resolveClassMethod");
return YES;
}
return NO;
}
+(BOOL)resolveInstanceMethod:(SEL)sel{
if (sel == @selector(messageTest)) {
NSLog(@"1======resolveInstanceMethod");
return YES;
}
return NO;
}
- (id)forwardingTargetForSelector:(SEL)aSelector {
if (aSelector == @selector(messageTest)) {
NSLog(@"2======forwardingTargetForSelector");
}
return nil;
}