Objective-C类的方法存储在何处以及如何存储?

Mic*_*man 4 methods objective-c objective-c-runtime

我知道当一个对象在堆上实例化时,至少分配足够的内存来保存对象的ivars.我的问题是编译器如何存储方法.内存中只有一个方法代码实例吗?或者代码是在内存中生成对象的固有部分,与ivars连续存储并执行?

似乎后者就是这种情况,即使像NSStrings这样的小事也需要(相对)大量的内存(也NSString从中继承方法NSObject).

或者该方法是在内存中存储一​​次并将指针传递给拥有它的对象?

dus*_*uff 8

在"标准"Objective-C运行时,每个对象在任何其他实例变量之前包含指向它所属的类的指针,就好像基类Object有一个名为的实例变量:

Class isa;
Run Code Online (Sandbox Code Playgroud)

给定类的每个对象共享相同的isa指针.

该类包含许多元素,包括指向父类的指针,以及方法列表数组.这些方法是专门在这个类上实现的方法.

struct objc_class {
    Class super_class;
    ...
    struct objc_method_list **methodLists;
    ...
};
Run Code Online (Sandbox Code Playgroud)

这些方法列表都包含一系列方法:

struct objc_method_list {
    int method_count;
    struct objc_method method_list[];
};

struct objc_method {
    SEL method_name;
    char *method_types;
    IMP method_imp;
};
Run Code Online (Sandbox Code Playgroud)

IMP这里的类型是一个函数指针.它指向存储方法实现的内存中的(单个)位置,就像任何其他代码一样.


注意:我在这里描述的实际上是ObjC 1.0运行时.当前版本不像这样存储类和对象; 它做了许多复杂,聪明的事情,使方法调用更快.但我所描述的仍然是它如何运作的精神,如果不是它的确切方式.

我还在其中一些结构中遗漏了几个字段,这些字段混淆了这种情况(例如,向后兼容性和/或填充).如果你想看到所有的血腥细节,请阅读真正的标题.

  • @MichaelZimmerman:是的,这正是它的工作原理.如果某个类中的任何列表中都没有方法,则运行时将继续在`super_class`中进行搜索. (3认同)
  • 正确 - 正如我在答案的底部所指出的那样,为了简单起见,我正在描述原始的ObjC运行时. (2认同)