• 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。

     
     
     
     
     
     
  • 相关阅读:
    django中的objects.get和objects.filter方法的区别
    Django之CSRF
    Django之include本质
    django中的FBV和CBV
    HTTP协议【详解】——经典面试题
    Python中的魔法函数__repr__和__str__的实质性区别
    浅谈CSS中的百分比
    深入理解定时器系列第一篇——理解setTimeout和setInterval
    Javascript学习
    HTML中块级元素和行内元素的总结和区分。
  • 原文地址:https://www.cnblogs.com/liuziyu/p/5733818.html
Copyright © 2020-2023  润新知