Runtime关于SEL、IMP、Method、isa、Class

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代替的是方法。

 

  1.         Class a =NSClassFromString(@"Human");  
  2.         Class b =NSClassFromString(@"man");   //通过类名获取类
  3.         //根据方法名say找到该方法的id,将sel与其绑定;  
  4.         SEL sel = NSSelectorFromString(@"say");  //通过方法名字符串获取方法等同 SEL sel = @selector(say);反之亦然可以通过SEL获取string的name。
  5.         [[a new] performSelector:sel];  
  6.         [[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方法的调用地址。

  1. IMP class_getMethodImplementation(Class cls, SEL sel)  
  2. {  
  3.     IMP imp;  
  4.   
  5.     if (!cls  ||  !sel) return NULL;  
  6.   
  7.     imp = lookUpMethod(cls, sel, YES/*initialize*/, YES/*cache*/);  
  8.   
  9.     // Translate forwarding function to C-callable external version  
  10.     if (imp == (IMP)&_objc_msgForward_internal) {  
  11.         return (IMP)&_objc_msgForward;  
  12.     }  
  13.   
  14.     return imp;  
  15. }

 

不同的类可以有相同的方法名,方法链表中根据方法名去查找具体的方法实现.
IMP 是一个函数指针, 这个被指向的函数包含一个接收消息的对象id(self指针), 调用方法的选标SEL(方法名), 及不定个数的方法参数, 并返回一个id。

BOOL class_addMethod(Class cls, SEL name, IMP imp, const char *types),给cls添加一个新的方法,若干cls存在这个方法则返回失败。

//源码

  1. BOOL class_addMethod(Class cls, SEL name, IMP imp, const charchar *types)  
  2. {  
  3.     if (!cls) return NO;  
  4.   
  5.     rwlock_write(&runtimeLock);  
  6.     IMP old = addMethod(newcls(cls), name, imp, types ?: "", NO);  
  7.     rwlock_unlock_write(&runtimeLock);  
  8.     return old ? NO : YES;  
  9. }

IMP class_replaceMethod(Class cls, SEL name, IMP imp, const char *types),替换cls的name方法的指针

  1. IMP class_replaceMethod(Class cls, SEL name, IMP imp, const charchar *types)  
  2. {  
  3.     if (!cls) return NULL;  
  4.   
  5.     return _class_addMethod(cls, name, imp, types, YES);  
  6. }

void method_exchangeImplementations(Method m1_gen, Method m2_gen),交换2个方法的实现指针。

IMP method_getImplementation(Method method),返回method的实现指针,其实就是返回method->imp。

  1. IMP method_getImplementation(Method m)  
  2. {  
  3.     return _method_getImplementation(newmethod(m));  
  4. }  
  5.   
  6. static IMP _method_getImplementation(method_t *m)  
  7. {  
  8.     if (!m) return NULL;  
  9.     return m->imp;  
  10. }

IMP method_setImplementation(Method method, IMP imp),设置方法的新的实现指针, 返回旧的实现指针。

method_getTypeEncoding(Method m),返回方法m的参数和返回值的描述的字串,这个就是直接返回m->types。

 
 
 
 
 
 

posted on 2016-08-03 17:40  自渔  阅读(426)  评论(0编辑  收藏  举报

导航