iOS面试题:Runtime中,SEL、Method 和 IMP
面试题:Runtime中,SEL、Method 和 IMP有什么区别,使用场景?
答:它们之间的关系可以这么解释:一个类(Class)持有一个分发表,在运行期分发消息,表中的每一个实体代表一个方法(Method),它的名字叫做选择子(SEL),对应着一种方法实现(IMP)。具体的分析如下:
-
SEL:定义:
typedef struct objc_selector *SEL
,代表方法的名称。仅以名字来识别。翻译成中文叫做选择子或者选择器,选择子代表方法在Runtime
期间的标识符。为SEL
类型,虽然SEL
是objc_selector
结构体指针,但实际上它只是一个C
字符串。在类加载的时候,编译器会生成与方法相对应的选择子,并注册到Objective-C
的Runtime
运行系统。不论两个类是否存在依存关系,只要他们拥有相同的方法名,那么他们的SEL
都是相同的。比如,有n
个viewcontroller
页面,每个页面都有一个viewdidload
,每个页面的载入,肯定都是不尽相同的。但是我们可以通过打印,观察发现,这些viewdidload
的SEL
都是同一个SEL sel = @selector(methodName);
// 方法名字NSLog(@"address = %p",sel);
// log输出为address = 0x1df807e29
因此类方法定义时,尽量不要用相同的名字,就算是变量类型不同也不行。否则会引起重复,例如:
-(void)setWidth:(int)width; -(void)setWidth:(double)width;
-
IMP:定义:
typedef id (*IMP)(id, SEL, ...)
,代表函数指针,即函数执行的入口。该函数使用标准的C
调用。第一个参数指向self
(它代表当前类实例的地址,如果是类则指向的是它的元类),作为消息的接受者;第二个参数代表方法的选择子;... 代表可选参数,前面的 id 代表返回值。 -
Method:定义:
typedef struct objc_method *Method
,Method
对开发者来说是一种不透明的类型,被隐藏在我们平时书写的类或对象的方法背后。它是一个objc_method
结构体指针,我们可以看到该结构体中包含一个SEL
和IMP
,实际上相当于在SEL
和IMP
之间作了一个映射。有了SEL
,我们便可以找到对应的IMP
,从而调用方法的实现代码。objc_method
的定义为:
/// Method
struct objc_method {
SEL method_name;
char *method_types;
IMP method_imp;
};
-
方法名
method_name
类型为SEL
,前面提到过相同名字的方法即使在不同类中定义,它们的方法选择器也相同。-
方法类型
method_types
是个char
指针,其实存储着方法的参数类型和返回值类型,即是Type Encoding
编码。 -
method_imp
指向方法的实现,本质上是一个函数的指针,就是前面讲到的Implementation
。
-
更多:iOS面试题 答案合集
更多:《BAT面试答案文集.PDF》,获取可加iOS技术交流圈:937194184,相互交流。