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