typedef struct objc_selector *SEL;
它是selector
在 Objc 中的表示(Swift 中是 Selector 类)。
selector 是方法选择器,其实作用就和名字一样,日常生活中,我们通过人名辨别谁是谁,注意 Objc 在相同的类中不会有命名相同的两个方法。
selector 对方法名进行包装,以便找到对应的方法实现。
首先看定义:Method 是一个包含方法信息的结构体
typedef struct objc_method *Method;
typedef struct objc_ method {
SEL method_name; //方法名类型
char *method_types; //参数和返回值的描述
IMP method_imp;//方法具体实现的指针
};
在runtime,oc的方法被称为Method结构体。
关于runtime Swizzling实质就是交换了IMP。
typedefstruct objc_class *Class;
struct objc_class {
Class isa; //指向对象所属的类
Class super_class; //指向父类的指针
const char *name;
long version;
long info;
long instance_size;
struct objc_ivar_list *ivars; //存储类的成员变量列表的结构体
struct objc_method_list **methodLists; //存储方法列表的结构体
struct objc_cache *cache;
struct objc_protocol_list *protocols; //协议列表
}
由此可见,我们可以动态修改 *methodList
的值来添加成员方法,这也是 Category 实现的原理,同样解释了 Category 不能添加属性的原因。添加属性需要动态绑定。
值得注意的时,objc_class
中的 isa 指针,这说明 Objc 类本身也是一个对象。为了处理类和对象的关系,Runtime 库创建了一种叫做 Meta Class(元类) 的东西,类对象所属的类就叫做元类。Meta Class 表述了类对象本身所具备的元数据。
我们所熟悉的类方法,就源自于 Meta Class。我们可以理解为类方法就是类对象的实例方法。每个类仅有一个类对象,而每个类对象仅有一个与之相关的元类。
所以,class可以灵活的代替别的类,SEL与其类似,不同的是SEL代替的是方法。
- Class a =NSClassFromString(@"Human");
- Class b =NSClassFromString(@"man"); //通过类名获取类
- //根据方法名say找到该方法的id,将sel与其绑定;
- SEL sel = NSSelectorFromString(@"say"); //通过方法名字符串获取方法等同 SEL sel = @selector(say);反之亦然可以通过SEL获取string的name。
- [[a new] performSelector:sel];
- [[b new] performSelector:sel]; //执行方法
class用于代替类,增加灵活性,因为我们不知道什么时候会用到什么类,方法也是如此,所以SEL可以代替方法,每个方法有方法名,ID,地址,相同的方法名,ID也一样,正常情况下我们根据方法名找到方法,用SEL方法可以根据ID找到方法,而用IMP方式可以直接找到地址,但是灵活性不如SEL方法,虽然效率最高。
IMP:IMP是”implementation”的缩写,它是objetive-C 方法(method)实现代码块的地址,可像C函数一样直接调用。通常情况下我们是通过[object method:parameter]或objc_msgSend()的方式向对象发送消息,然后Objective-C运行时(Objective-C runtime)寻找匹配此消息的IMP,然后调用它。
IMP class_getMethodImplementation(Class cls, SEL name),返回cls的name方法的调用地址。
- IMP class_getMethodImplementation(Class cls, SEL sel)
- {
- IMP imp;
- if (!cls || !sel) return NULL;
- imp = lookUpMethod(cls, sel, YES/*initialize*/, YES/*cache*/);
- // Translate forwarding function to C-callable external version
- if (imp == (IMP)&_objc_msgForward_internal) {
- return (IMP)&_objc_msgForward;
- }
- return imp;
- }
不同的类可以有相同的方法名,方法链表中根据方法名去查找具体的方法实现.
IMP 是一个函数指针, 这个被指向的函数包含一个接收消息的对象id(self指针), 调用方法的选标SEL(方法名), 及不定个数的方法参数, 并返回一个id。
BOOL class_addMethod(Class cls, SEL name, IMP imp, const char *types),给cls添加一个新的方法,若干cls存在这个方法则返回失败。
//源码
- BOOL class_addMethod(Class cls, SEL name, IMP imp, const charchar *types)
- {
- if (!cls) return NO;
- rwlock_write(&runtimeLock);
- IMP old = addMethod(newcls(cls), name, imp, types ?: "", NO);
- rwlock_unlock_write(&runtimeLock);
- return old ? NO : YES;
- }
IMP class_replaceMethod(Class cls, SEL name, IMP imp, const char *types),替换cls的name方法的指针
- IMP class_replaceMethod(Class cls, SEL name, IMP imp, const charchar *types)
- {
- if (!cls) return NULL;
- return _class_addMethod(cls, name, imp, types, YES);
- }
void method_exchangeImplementations(Method m1_gen, Method m2_gen),交换2个方法的实现指针。
IMP method_getImplementation(Method method),返回method的实现指针,其实就是返回method->imp。
- IMP method_getImplementation(Method m)
- {
- return _method_getImplementation(newmethod(m));
- }
- static IMP _method_getImplementation(method_t *m)
- {
- if (!m) return NULL;
- return m->imp;
- }