iOS面试题swift 基础

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

2020-03-12  本文已影响0人  EmulatingStep

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

  • 实例方法:每个实例的isa指针指向着对应类对象,而每一个类对象中都一个对象方法列表。
  • 类方法:每个类对象的isa指针都指向着对应的元类对象,而每一个元类对象中都有一个类方法列表。
  • 当我们发送一个消息给一个NSObject对象时,这条消息会在对象的类对象方法列表里查找。
  • 当我们发送一个消息给一个类时,这条消息会在类的meta class对象的方法列表里查找。

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调用。

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;  // 函数指针。
    } 

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


iOS面试题汇总

上一篇下一篇

猜你喜欢

热点阅读