IOS SEL
其中@selector()是取类方法的编号,取出的结果是SEL类型。
SEL:类成员方法的指针,与C的函数指针不一样,函数指针直接保存了方法的地址,而SEL只是方法的编号。
说一下C的函数指针:
int addOne(int val)
{
return val + 1;
}
int main(int argc, char *argv[]) {
int (*p)(int val);//定义一个函数指针
p = addOne;//p 指向addOne的地址
cout<<"result :"<<(*p)(5)<<endl;//直接通过函数指针调用函数
}
objective-c 中时:
Objective-C 在编译的时候,会根据方法的名字(包括参数)生成一个用来区分这个方法的唯一的ID,就是这个方法的编号,而这个ID就是SEL类型的。方法和参数相同的时候产生的函数ID是一样的,于是不管两个类之间是否存在继承关系,只要方法名和参数序列一样,方法的的ID便一样。
1、获取方法编号的方法:
SEL methodId = @selector(func);
2、获取方法编号之后执行方法
[self performSelector: methodId withObject: nil];
3、通过编号获取方法
NSString *methodName = NSStringFromSelector(methodId);
4、IMP的获得和使用
IMP methodPoint = [self methodForSelector: methodId];
methodPoint();//函数指针的调用
5、为什么不直接获取函数指针,而是要从SEL这个方法ID绕回到函数指针?
一个SEL指向不同的函数指针,就可以完成一个方法名在不同时候执行不同的函数体。可以将SEL作为参数传递给不同的类执行。
IMP
IMP是函数指针,指向方法的地址。
id object = getTheObject();
SEL fun = getFunMethod();
[object performSelector: fun];
我们在程序中这样写,是为了将消息接收对象和接收对象的方法动态,因为objective-c的方法调用最后都会归结到消息传递上,即这个方法objc_msgSend()上。我们可以看出上面的实现是基于runtime的,在类中,存在一个isa 指针,指向类定义的数据结构体,这个结构体是编译的时候编译器为类创建的(需继承NSObject),这个结构体包括指向其父类类定义的指针、dispatch table,而dispatch table 便是一张 SEL 和IMP的对应表。
SEL 方法编号最后通过Diapatch table 表寻找到对应方法额IMP(地址),IMP就是函数指针,然后执行这个方法。
接着上面的方法名相同(不包括类名称),这时的SEL 的函数ID是相同的,即父类和子类中同名的方法拥有相同的SEL,而两个方法的实现可以各不相同,因而在他们各自对应的Dispatch 表中SEL对应的IMP是不同的,IMP是函数的指针,而虽然每一个SEL对象的是一个方法的名称,但是考虑到效率,SEL本身是整形,编译器会生成一张SEL和方法名称对应的表。
[myObject fun1:6];
首先在myObject的空间结构中的idspatch table中插好啊对应的SEL,如果有就表示myObject有响应的方法,程序就跳转到该方法的代码地址头(IMP 指定),开始执行,如果在myObject的Dispatch table 找不到对应的SEL,那么就会通过isa所指的结构体中包含的父类指针,到父类中去寻找,如果最后还是没有找到就会出现erroe的错误。
类的方法可以在执行的时候创建。
class _addMethod([MyClass Class], @selector(dynMethod:), (IMP)myClassIMP,"Hello");
在给MyClass类在执行时增加一个响应dynMethod:消息的方法,这样之后对任何MyClass的instance类发送dynMethod:消息,就会得到相应,.myClassIMP是类收到该消息时要调用的方法,生命如下:
myClassIMP(id, _rec, SEL _cmd, int theInt);
函数前两个参数是必须的,后面的两个是实际用到的参数,参数的个数和@selector()中冒号的个数一样,第一个参数代表消息的结构对象,是myClass的实例对象,第二个参数是由SEL代表的具体的消息。
方法名称不包括返回类型、参数类型,而又因为方法名相同对应的SEL相同,所以Objc不支持相同的方法名有不同的返回类型,也不支持重载,不过类方法和实例方法可以有相同的名字,而又有不同类型的参数和返回类型,因为它们不是处在同一张diapatch table中。
不仅类的方法可以在运行时创建,类本身也可以在运行时刻创建,只要类继承NSObject类。