Objective-C 选择器 registered/stored 在哪里?

Where are Objective-C selectors registered/stored?

我不太明白 Objective-C 选择器。 问题是:Objective-C 选择器存储在哪里?

Objective-C 编译器和运行时系统如何工作,以便将方法名称转换为 SEL?

看看Apples explanation:

A selector is the name used to select a method to execute for an object, or the unique identifier that replaces the name when the source code is compiled. A selector by itself doesn’t do anything. It simply identifies a method. The only thing that makes the selector method name different from a plain string is that the compiler makes sure that selectors are unique. What makes a selector useful is that (in conjunction with the runtime) it acts like a dynamic function pointer that, for a given name, automatically points to the implementation of a method appropriate for whichever class it’s used with. Suppose you had a selector for the method run, and classes Dog, Athlete, and ComputerSimulation (each of which implemented a method run). The selector could be used with an instance of each of the classes to invoke its run method—even though the implementation might be different for each.

如果你看一下@AntoniKedracki post,关于 methodsselectors 的解释非常好。

post 的简短摘要:

每个 objective-c 方法都将在 c 中的 struct 中表示。该结构如下所示:

struct objc_method {
    SEL method_name                                          
    char *method_types                                       
    IMP method_imp                                           
} 

因此选择器将由 C 根据方法名称自动创建并保存在 SEL method_name 中。如果您想访问 objc_method,您应该包含 <objc/runtime.h>,然后您将能够使用运行时方法。

有关更多信息,请查看其他 post 中的 link。

选择器是 "interned"(统一的)字符串。运行时维护一个内部字符串池(选择器)。如果你想实习一个字符串,你可以使用 C 字符串调用 sel_getUid()sel_registerName() 运行时函数,并且它 returns 一个 SEL 类型的不透明句柄(选择器)。如果该字符串之前已经被驻留,则该选择器保证与前一个选择器相等。相反,您可以使用 sel_getName() 从选择器中取回字符串。在 Cocoa 中,您将使用 NSSelectorFromString()NSStringFromSelector(),它们对 NSString 对象进行操作,而不是使用上述低级运行时函数。

大多数时候,您不会在程序中间进行字符串和选择器之间的转换。相反,选择器在编译时已经被硬编码。当你执行像 [foo something: bar] 这样的方法调用时,它会被编译成像 objc_msgSend(foo, @selector(something:), bar) 这样的东西,而像 @selector(something:) 这样的选择器文字将被编译成对二进制选择器 [=27= 的引用] 由编译器生成,类似于全局变量。链接模块时,其选择器table与主程序的选择器table合并,以保证选择器的唯一性。

同样的问题也困扰了我一段时间。所以我研究了运行时实现。这就是我发现的:

所有选择器都存储在一个哈希集中。如果您已经有一个已注册的选择器,它将由 objc 运行时使用 c 函数 sel_getUid & sel_registerName 返回,如果未注册,它将由相同的函数创建。它们都具有相同的实现和行为,因为它们正在调用名为 __sel_registerName 的私有函数。旧运行时使用指向结构 __objc_sel_set 的指针来存储值。

struct __objc_sel_set {
uint32_t _count;            /* number of slots used */
uint32_t _capacity;         /* maximum number of used slots */
uint32_t _bucketsNum;       /* number of slots */
SEL *_buckets;              /* can be NULL if not allocated yet */
};

新运行时使用指向结构 NXMapTable 的指针:

typedef struct _NXMapTable {
/* private data structure; may change */
const struct _NXMapTablePrototype   *prototype;
unsigned    count;
unsigned    nbBucketsMinusOne;
void    *buckets;
} NXMapTable OBJC_MAP_AVAILABILITY;

希望对您有所帮助。