美文网首页iOS面试题swift 基础
runtime 如何通过 selector 找到对应的 IMP

runtime 如何通过 selector 找到对应的 IMP

作者: EmulatingStep | 来源:发表于2020-03-12 10:41 被阅读0次

    实例方法类方法的存储位置:

    • 实例方法:每个实例的isa指针指向着对应类对象,而每一个类对象中都一个对象方法列表。
    • 类方法:每个类对象的isa指针都指向着对应的元类对象,而每一个元类对象中都有一个类方法列表。
    • 当我们发送一个消息给一个NSObject对象时,这条消息会在对象的类对象方法列表里查找。
    • 当我们发送一个消息给一个类时,这条消息会在类的meta class对象的方法列表里查找。
    • 方法列表中记录着一个个方法实体(结构体Method),实体中包含方法的名称,方法实现,以及参数类型。
    • 其实selector本质就是C字符串的方法名称(见下面分析),通过这个方法名称就可以在方法列表中找到方法实体,进一步找到对应的方法实现。

    Selector,Method 和 IMP 的区别与联系

    Selector
    定义:

    typedef struct objc_selector *SEL
    

    翻译成中文叫做选择子或者选择器,选择子代表方法在Runtime期间的标识符。为SEL类型,虽然SELobjc_selector结构体指针,但实际上它只是一个C字符串。在类加载的时候,编译器会生成与方法相对应的选择子,并注册到Objective-CRuntime运行系统。

    常见的有两种方式来获取/创建选择子:

    SEL selA = @selector(setString:);
    SEL selB = sel_registerName("setString:"); 
    

    在控制台测试:

    (lldb) p selA
    (SEL) $1 = "setString:"
    (lldb) p selB
    (SEL) $2 = "setString:"
    

    两者打印出来的都是字符串。

    我们从sel_getName()方法的源码可以看出SELconst char *是可以相互转化的:

    const char *sel_getName(SEL sel) {
       return sel ? (const char *)sel : "<null selector>";
    }
    

    如果将selAselB强转为为const char *

    (lldb) p (const char *)$2
    (const char *) $3 = 0x00007fff9a3794b5 "setString:"
    (lldb) p (const char *)$1
    (const char *) $4 = 0x00007fff9a3794b5 "setString:"
    (lldb) 
    

    上面的结果可以看出,selAselB指向相同的地址,代表同一个字符串。

    如果某个类实现了setString:方法,那么以上两个选择子传入 respondsToSelector()方法返回的结果都将为YES

    不同类中相同名字的方法所对应的方法选择子是相同的。

    Implementation(IMP):
    定义:

    typedef id (*IMP)(id, SEL, ...)
    

    代表函数指针,即函数执行的入口。该函数使用标准的C调用。

    • 第一个参数指向self(它代表当前类实例的地址,如果是类则指向的是它的元类),作为消息的接受者;
    • 第二个参数代表方法的选择子;
    • ...代表可选参数;
    • 前面的id代表返回值。

    Method
    定义:

    typedef struct objc_method *Method
    

    Method 对开发者来说是一种不透明的类型,它是一个objc_method结构体指针,objc_method的定义为:

    /// An opaque type that represents a method in a class definition.
        typedef struct 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

    SelectorMethodIMP它们之间的关系可以这么解释:
    一个类(Class)持有一个方法列表,在运行期分发消息,表中的每一个实体代表一个方法(Method),它的名字叫做选择子(SEL),对应着一种方法实现(IMP


    iOS面试题汇总

    相关文章

      网友评论

        本文标题:runtime 如何通过 selector 找到对应的 IMP

        本文链接:https://www.haomeiwen.com/subject/ptxyjhtx.html