简体   繁体   English

Objective-C选择器在哪里注册/存储?

[英]Where are Objective-C selectors registered/stored?

I don't quite get the Objective-C selectors. 我不太了解Objective-C选择器。 The problem is: Where are Objective-C selectors stored ? 问题是:Objective-C选择器存储在哪里?

How do Objective-C Compiler and Runtime System work, so that they convert the method names into SEL ? Objective-C编译器和运行时系统如何工作,以便将方法名称转换为SEL?

Selectors are "interned" (uniquified) strings. 选择器是“实习”(未加工)的字符串。 The runtime maintains a pool of interned strings (selectors). 运行时维护一个实习字符串池(选择器)。 If you want to intern a string, you call either the sel_getUid() or the sel_registerName() runtime function with a C string, and it returns an opaque handle of type SEL (the selector). 如果要实习字符串,则使用C字符串调用sel_getUid()sel_registerName()运行时函数,并返回SEL类型的不透明句柄(选择器)。 If the string has already been interned before, this selector is guaranteed to be equal to the previous one. 如果字符串之前已经被中断,则此选择器保证等于前一个。 Conversely, from a selector you can get the string back using sel_getName() . 相反,从选择器中,您可以使用sel_getName()获取字符串。 In Cocoa you would use NSSelectorFromString() and NSStringFromSelector() , which operate on NSString objects, instead of using the above low-level runtime functions. 在Cocoa中,您将使用NSSelectorFromString()NSStringFromSelector() ,它们对NSString对象进行操作,而不是使用上述低级运行时函数。

Most of the time, you will not be doing conversion between strings and selectors in the middle of your program. 大多数情况下,您不会在程序中间进行字符串和选择器之间的转换。 Instead, the selector will have already been hard-coded at compile-time. 相反,选择器在编译时已经被硬编码了。 When you do a method call like [foo something: bar] , it is compiled down into something like objc_msgSend(foo, @selector(something:), bar) , and the selector literal like @selector(something:) will be compiled into a reference into the binary's selector table generated by the compiler, similar to with global variables. 当你执行像[foo something: bar]这样的方法调用时,它被编译成类似objc_msgSend(foo, @selector(something:), bar) ,而像@selector(something:)这样的选择器文字将被编译成对编译器生成的二进制选择器表的引用,类似于全局变量。 When a module is linked, its selector table is merged with the main program's selector table to guarantee the uniqueness of selectors. 链接模块时,其选择器表与主程序的选择器表合并,以保证选择器的唯一性。

The same question was bothering me too for a while. 同样的问题也困扰了我一段时间。 So I've looked into the runtime implementation. 所以我研究了运行时实现。 That's what I've found: 这就是我发现的:

All the selectors are stored in a hash set. 所有选择器都存储在哈希集中。 If you already have a registered selector, it will be returned by the objc runtime using c functions sel_getUid & sel_registerName, if not registered, it will be created by the same functions. 如果您已经有一个已注册的选择器,它将由objc运行时使用c函数sel_getUid和sel_registerName返回,如果未注册,它将由相同的函数创建。 Both of them have the same implementation & behavior, 'cause they are calling private function named __sel_registerName. 它们都具有相同的实现和行为,因为它们正在调用名为__sel_registerName的私有函数。 Old runtime uses pointer to struct __objc_sel_set to store values. 旧运行时使用指向struct __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 */
};

New runtime uses pointer to struct NXMapTable: 新运行时使用指向struct NXMapTable的指针:

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

Hope this helps. 希望这可以帮助。

Have a look at Apples explanation : 看看Apples解释

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). 假设你有一个方法运行的选择器,以及类Dog,Athlete和ComputerSimulation(每个都实现了一个方法运行)。 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. 选择器可以与每个类的实例一起使用以调用其run方法 - 即使每个类的实现可能不同。

If you have a look at @AntoniKedracki post there is a really good explanation about methods and selectors . 如果你看一下@AntoniKedracki的帖子,对methodsselectors有一个非常好的解释。

Just a short summary from the post: 只是帖子的简短摘要:

Every objective-c method will be represented inside a struct in c . 每个objective-c方法都将在cstruct中表示。 The struct looks like this: 结构看起来像这样:

struct objc_method {
    SEL method_name                                          
    char *method_types                                       
    IMP method_imp                                           
} 

So the selector will be created by C automatically from the method name and saved inside the SEL method_name . 因此,选择器将由C自动从方法名称创建并保存在SEL method_name If you want to get access to the objc_method you should include the <objc/runtime.h> , than you will be able to use the runtime methods. 如果要访问objc_method ,则应该包含<objc/runtime.h> ,而不是可以使用运行时方法。

For more information have a look at the link in the other post. 有关更多信息,请查看其他帖子中的链接。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM