Runtime--Selector、IMP、Method

Selector

Selector的类型是SEL。能够用来唯一标识方法。能够像动态的函数指针一样精准的指向方法的implementation。

获取方法

在编译期,使用编译器指令@@selector,例如

SEL aSelector = @selector(methodName);

在运行期,使用NSSelectorFromString函数,例如

SEL aSelector = NSSelectorFromString(@"methodName");

使用方法

一下方法在NSObject类中声明

- (id)performSelector:(SEL)aSelector;
- (id)performSelector:(SEL)aSelector withObject:(id)object;
- (id)performSelector:(SEL)aSelector withObject:(id)object1 withObject:(id)object2;

与Runtime

首先定义一个方法

-(void)getMethod:(NSString *)name
{
    NSLog(@"getMethod:%@",name);
}

然后获取方法

SEL sel = @selector(getMethod:);
SEL sel2 = NSSelectorFromString(@"getMethod:");
获取方法名称
 //获取名称
const char *sel_name = sel_getName(sel);
NSLog(@"SEL sel_name:%@",[NSString stringWithUTF8String:sel_name]);

//输出
SEL sel_name:ivarMethod
注册方法
//在添加一个Method之前需要先注册一个;如果方法已注册直接返回
SEL sel_registerName(const char *str)

//或者
SEL sel_getUid(const char *str)

例如

//注册
SEL sel_regist = sel_registerName("sel_regist");
NSLog(@"SEL sel_regist:%@",NSStringFromSelector(sel_regist));

SEL sel_regist2 =sel_getUid("sel_regist");
NSLog(@"SEL sel_regist2:%@",NSStringFromSelector(sel_regist2));

//输出
SEL sel_regist:sel_regist
SEL sel_regist2:sel_regist
比较方法
//相等于符号 == 
BOOL sel_isEqual(SEL lhs, SEL rhs) 

例如

//比较
BOOL isEqual = sel_isEqual(sel_regist2, sel_regist2);
NSLog(@"SEL isEqual:%d",isEqual);

//输出
SEL isEqual:1    

IMP(Implementation)

一个指向实现Method的函数的开始的指针。此函数使用标准的C语言调用习惯来实现CGU架构。其实参数:self、selector、其它Method参数。其中实例方法而言,self指向对象的内存地址;对于类方法而言self指向其metaclass。

Method

此处讨论Method与Runtime相关的指示。首先定义一个简单的Data类,声明并实现一些方法

@interface Data : NSObject

-(void)getMethod:(NSString *)name;
-(void)ivarMethod;
+(void)classMethod;

@end


@implementation Data
-(void)ivarMethod
{
    NSLog(@"调用ivarMethod");
}
+(void)classMethod
{
    NSLog(@"调用classMethod");

}

-(void)getMethod:(NSString *)name
{
    NSLog(@"getMethod:%@",name);
}
@end

获取Method

注释:不管在header文件还是implement文件声明实现的方法均可以获取到。

获取实例Method
 Method ivar_Method = class_getInstanceMethod([Data class], @selector(ivarMethod));
 SEL sel_ivar_Method = method_getName(ivar_Method);
 NSLog(@"Method class_getInstanceMethod:%@",NSStringFromSelector(sel_ivar_Method));

//输出
class_getInstanceMethod:ivarMethod
获取类Method
/* 获取类方法 */
Method class_Method = class_getClassMethod([Data class], @selector(classMethod));
SEL sel_class_Method = method_getName(class_Method);
NSLog(@"Method class_getClassMethod:%@",NSStringFromSelector(sel_class_Method));

//输出
Method class_getClassMethod:classMethod    
获取实例Method列表
/** 
 * 获取类的实例方法列表
 * 
 * @return 以数组想法返回实例方法列表(需要free);只返回类本身实现的方法,不包括父类的继承的方法。 
 *   
 * 获取类方法列表: class_copyMethodList(object_getClass(cls), &count).
 * 获取父类方法:class_getInstanceMethod 或 class_getClassMethod.
 */
Method *class_copyMethodList(Class cls, unsigned int *outCount);
/* 获取实例方法列表 */
unsigned int count_method = 0;
Method *method_list = class_copyMethodList([Data class], &count_method);
for (int i = 0; i < count_method; i ++)
{
   Method method = method_list[i];
   SEL sel_Method = method_getName(method);
   NSLog(@"Method class_copyMethodList:%@",NSStringFromSelector(sel_Method));

}

//输出
Method class_copyMethodList:ivarMethod
Method class_copyMethodList:getMethod:
获取类Method列表
/* 获取实例方法列表 */
unsigned int count_method = 0;
Method *method_list = class_copyMethodList(object_getClass([Data class]), &count_method);
for (int i = 0; i < count_method; i ++)
{
   Method method = method_list[i];
   SEL sel_Method = method_getName(method);
   NSLog(@"Method class_copyMethodList:%@",NSStringFromSelector(sel_Method));

}

//输出
Method class_copyMethodList:classMethod

Method属性获取和操作

首先以实例方法为例子获取一个Method
Method ivar_Method = class_getInstanceMethod([Data class], @selector(getMethod:));

方法调用
/* 
 * This is faster than calling method_getImplementation() and method_getName().
 *
 * receiver 不能为空
 * 函数必须先转换成合适的函数指针,然后才能调用
 */
void method_invoke(void /* id receiver, Method m, ... */ ) ;

例如调用@selector(getMethod:)

((void(*)(id,Method,id))method_invoke)([[Data alloc] init], ivar_Method,@"方法调用");

//输出
getMethod:方法调用

例如调用@selector(ivarMethod)

Method ivar_Method = class_getInstanceMethod([Data class], @selector(ivarMethod));
((void(*)(id, Method))method_invoke)([[Data alloc] init], ivar_Method);

//输出
调用ivarMethod

例如调用类方法@selector(classMethod)

Method class_Method = class_getClassMethod([Data class], @selector(classMethod));
//object_getClass([Data class])原理是类方法是去Metaclass寻找的
((void(*)(id,Method))method_invoke)(object_getClass([Data class]),class_Method);

//输出
调用classMethod

关于函数指针的简单说明:
1、void 表示返回值为空
2、(*)表明是个函数指针
3、函数指针指向函数的内存地址((void(*)(id,Method))method_invoke)
4、函数指针的调用方式可以自行查阅资料

void add(int a,int b)
{
    int c = a+b;
    NSLog(@"%d",c);

}

//声明函数指针
void (*add2)(int,int);
//赋值
add2 = &add;
//调用
(*add2)(3,4);
((void(*)(int, int))add)(3, 4);

NSLog(@"%p--%p",&add,((void (*)(int, int))add));

//输出
7
7
0x107022970--0x107022970
获取名称
//获取名称
SEL sel_ivar_Method = method_getName(ivar_Method);
NSLog(@"Method class_getInstanceMethod:%@",NSStringFromSelector(sel_ivar_Method));

//输出
Method class_getInstanceMethod:getMethod:
获取IMP
//获取imp
IMP method_imp = method_getImplementation(ivar_Method);
获取返回值、参数类型
const char* method_TypeEncoding = method_getTypeEncoding(ivar_Method);
NSLog(@"method_TypeEncoding:%@",[NSString stringWithUTF8String:method_TypeEncoding]);

//输出
method_TypeEncoding:v24@0:8@16
获取返回值类型
//获取返回值类型
const char* method_ReturnType = method_copyReturnType(ivar_Method);
NSLog(@"method_ReturnType:%@",[NSString stringWithUTF8String:method_ReturnType]);
//C语言获取方法 method_getReturnType(<#Method m#>, <#char *dst#>, <#size_t dst_len#>)

//输出
method_ReturnType:v
获取参数个数、类型
//获取参数个数
unsigned int numberOfArguments = method_getNumberOfArguments(ivar_Method);
NSLog(@"numberOfArguments:%d",numberOfArguments);

//获取参数类型
unsigned int number = method_getNumberOfArguments(ivar_Method);
for ( int i = 0; i < number ; i ++)
{
   const char *type = method_copyArgumentType(ivar_Method, i);
   NSLog(@"ArgumentType:%@",[NSString stringWithUTF8String:type]);
}
 //C语言获取方法 method_getArgumentType(<#Method m#>, <#unsigned int index#>, <#char *dst#>, <#size_t dst_len#>)

//输出:@表示id类型 :表示Selector
numberOfArguments:3
ArgumentType:@
ArgumentType::
ArgumentType:@
获取描述
//获取描述
struct objc_method_description *method_descriptions = method_getDescription(ivar_Method);
struct objc_method_description method_description = method_descriptions[0];
SEL sel_des = method_description.name;
const char *type_des = method_description.types;
NSLog(@"objc_method_description:%@  types:%@",NSStringFromSelector(sel_des),[NSString stringWithUTF8String:type_des]);

//输出
objc_method_description:getMethod:  types:v24@0:8@16
设置IMP
IMP imp_new = class_getMethodImplementation([Data class], @selector(ivarMethod));
IMP imp_old = method_setImplementation(ivar_Method, imp_new);
((void(*)(id,Method,id))method_invoke)([[Data alloc] init], ivar_Method,@"方法调用");

//原来输出
getMethod:方法调用
//现在输出
调用ivarMethod

交换IMP
//交换
//用来交换的Method
Method ivar_Method2 = class_getInstanceMethod([Data class], @selector(ivarMethod));

//交换前调用
((void(*)(id,Method,id))method_invoke)([[Data alloc] init], ivar_Method,@"方法调用");
((void(*)(id,Method))method_invoke)([[Data alloc] init], ivar_Method2);

//交换
method_exchangeImplementations(ivar_Method, ivar_Method2);

//交换前调用
((void(*)(id,Method,id))method_invoke)([[Data alloc] init], ivar_Method,@"方法调用");
((void(*)(id,Method))method_invoke)([[Data alloc] init], ivar_Method2);

//输出结果
getMethod:方法调用
调用ivarMethod

调用ivarMethod
getMethod:<Data: 0x60800000d290>

添加Method

/** 
 * @param cls 目标类
 * @param name SEL
 * @param imp 新方法的实现函数,至少两个参数:self and _cmd.
 * @param types 参数类型列表  
 * 
 * @return 如果成功返回YES,否则NO(例如,已存在) 
 *  
 *
 * @note 可以覆盖父类方法,不改变自己已有方法(返回NO);改变已有方法:method_setImplementation。
 */
OBJC_EXPORT BOOL class_addMethod(Class cls, SEL name, IMP imp, 
                                 const char *types) 

关于types的说明请参考Type Encodings,返回值类型+self+_cmd+其他参数s:v@:其他参数符号s

添加实例Method
//新增方法
-(void)ivarMethod2
{
    NSLog(@"ivarMethod2");
}

/* 添加方法 */
IMP imp_add = class_getMethodImplementation([self class], @selector(ivarMethod2));
BOOL isadd =  class_addMethod([Data class], @selector(ivarMethod2), imp_add, "v@:");
NSLog(@"isadd:%d",isadd);

/* 检测添加结果 */
unsigned int count_method = 0;
Method *method_list = class_copyMethodList([Data class], &count_method);
for (int i = 0; i < count_method; i ++)
{
   Method method = method_list[i];
   SEL sel_Method = method_getName(method);
   NSLog(@"Method class_copyMethodList:%@",NSStringFromSelector(sel_Method));
}

//输出结果
isadd:1
Method class_copyMethodList:ivarMethod2//添加成功
Method class_copyMethodList:getMethod:
Method class_copyMethodList:ivarMethod
添加类Method
//新增方法
+(void)classMethod2
{
    NSLog(@"classMethod2");
}

/* 添加类方法 */
IMP imp_add = class_getMethodImplementation([self class], @selector(classMethod2));
BOOL isadd =  class_addMethod(object_getClass([Data class]), @selector(classMethod2), imp_add, "v@:");
NSLog(@"isadd:%d",isadd);

/* 检测添加结果 */
unsigned int count_method = 0;
Method *method_list = class_copyMethodList(object_getClass([Data class]), &count_method);
for (int i = 0; i < count_method; i ++)
{
   Method method = method_list[i];
   SEL sel_Method = method_getName(method);
   NSLog(@"Method class_copyMethodList:%@",NSStringFromSelector(sel_Method));
}

//输出结果
isadd:1
Method class_copyMethodList:ivarMethod2
Method class_copyMethodList:classMethod2//添加成功
Method class_copyMethodList:classMethod

替换Method

/** 
 * 
 * @param cls 目标类
 * @param name SEL
 * @param imp 新方法的实现函数
 * @param types 参数类型列表 
 * @return 旧的IMP
 * 
 * @note 两种情况:
 *  - 如果方法不存在,执行 class_addMethod  
 *    
 *  - 如果方法存在,执行method_setImplementation
 *    
 */
OBJC_EXPORT IMP class_replaceMethod(Class cls, SEL name, IMP imp, 
                                    const char *types) 

例如

/* 替换方法 */    
Method ivar_Method = class_getInstanceMethod([Data class], @selector(ivarMethod));

//执行前
((void(*)(id,Method))method_invoke)([[Data alloc] init], ivar_Method);

//方法替换
IMP imp_new = class_getMethodImplementation([self class], @selector(ivarMethod2));
IMP imp_old = class_replaceMethod([Data class], @selector(ivarMethod), imp_new, "v@:");

//执行后
((void(*)(id,Method))method_invoke)([[Data alloc] init], ivar_Method);

//输出结果
调用ivarMethod//原来
ivarMethod2//交换后

是否响应

/* 响应 */
BOOL isResponse = class_respondsToSelector([Data class], @selector(ivarMethod));
NSLog(@"isResponse:%d",isResponse);

//输出结果 
isResponse:1
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值