Objective-C 选择器 registered/stored 在哪里?
Where are Objective-C selectors registered/stored?
我不太明白 Objective-C 选择器。
问题是:Objective-C 选择器存储在哪里?
Objective-C 编译器和运行时系统如何工作,以便将方法名称转换为 SEL?
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,关于 methods
和 selectors
的解释非常好。
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;
希望对您有所帮助。
我不太明白 Objective-C 选择器。 问题是:Objective-C 选择器存储在哪里?
Objective-C 编译器和运行时系统如何工作,以便将方法名称转换为 SEL?
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,关于 methods
和 selectors
的解释非常好。
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;
希望对您有所帮助。