我不太了解Objective-C选择器。 问题是:Objective-C选择器存储在哪里?
Objective-C编译器和运行时系统如何工作,以便将方法名称转换为SEL?
答案 0 :(得分:3)
选择器是“实习”(未加工)的字符串。运行时维护一个实习字符串池(选择器)。如果要实习字符串,可以使用C字符串调用sel_getUid()
或sel_registerName()
运行时函数,并返回类型为SEL
的不透明句柄(选择器)。如果字符串之前已经被中断,则此选择器保证等于前一个。相反,您可以使用sel_getName()
从选择器中获取字符串。在Cocoa中,您将使用NSSelectorFromString()
和NSStringFromSelector()
,它们对NSString
个对象进行操作,而不是使用上述低级运行时函数。
大多数情况下,您不会在程序中间进行字符串和选择器之间的转换。相反,选择器在编译时已经被硬编码了。当您执行类似[foo something: bar]
的方法调用时,它会被编译为类似objc_msgSend(foo, @selector(something:), bar)
的内容,而像@selector(something:)
这样的选择器文字将被编译成对二进制文件生成的选择器表的引用。编译器,类似于全局变量。链接模块时,其选择器表与主程序的选择器表合并,以保证选择器的唯一性。
答案 1 :(得分:3)
同样的问题也困扰了我一段时间。所以我研究了运行时实现。这就是我发现的:
所有选择器都存储在哈希集中。如果您已经有一个已注册的选择器,它将由objc运行时使用c函数sel_getUid& sel_registerName,如果没有注册,它将由相同的函数创建。它们都具有相同的实现和行为,因为他们正在调用名为__sel_registerName的私有函数。旧运行时使用指向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 */
};
新运行时使用指向struct NXMapTable的指针:
typedef struct _NXMapTable {
/* private data structure; may change */
const struct _NXMapTablePrototype *prototype;
unsigned count;
unsigned nbBucketsMinusOne;
void *buckets;
} NXMapTable OBJC_MAP_AVAILABILITY;
希望这有帮助。
答案 2 :(得分:1)
选择器是用于选择要为对象执行的方法的名称,或者是在编译源代码时替换名称的唯一标识符。选择器本身不做任何事情。它只是识别一种方法。使选择器方法名称与普通字符串不同的唯一因素是编译器确保选择器是唯一的。使选择器有用的原因是(与运行时一起)它就像一个动态函数指针,对于给定的名称,它自动指向适用于它所使用的任何类的方法的实现。假设你有一个方法运行的选择器,以及类Dog,Athlete和ComputerSimulation(每个都实现了一个方法运行)。选择器可以与每个类的实例一起使用来调用其run方法 - 即使每个类的实现可能不同。
如果您看一下@AntoniKedracki帖子,就methods
和selectors
提供了非常好的解释。
该帖子的简短摘要:
每个objective-c方法都会在struct
中的c
内展示。结构看起来像这样:
struct objc_method {
SEL method_name
char *method_types
IMP method_imp
}
因此选择器将由C
自动从方法名称创建并保存在SEL method_name
内。如果您想要访问objc_method
,那么您应该包含<objc/runtime.h>
,而不是您可以使用运行时方法。
有关详细信息,请查看其他帖子中的链接。