Dav*_*des 7 iphone objective-c selector
我想把一组矩形与相应的动作联系起来,所以我试着这样做
struct menuActions {
CGRect rect;
SEL action;
};
struct menuActions someMenuRects[] = {
{ { { 0, 0 }, {320, 60 } }, @selector(doSomething) },
{ { { 0, 60}, {320, 50 } }, @selector(doSomethingElse) },
};
Run Code Online (Sandbox Code Playgroud)
但我得到错误"初始化元素不是常数".是否有某些原因使我想要做的事情一般不被允许,或者在全球范围内不被允许,或者我是否有某种轻微的标点错误?
joh*_*hne 23
这个答案就是为什么"initializer element is not constant".
给出以下示例:
SEL theSelector; // Global variable
void func(void) {
theSelector = @selector(constantSelector:test:);
}
Run Code Online (Sandbox Code Playgroud)
为这个i386架构编译成这样的东西:
.objc_meth_var_names
L_OBJC_METH_VAR_NAME_4:
.ascii "constantSelector:test:\0"
.objc_message_refs
.align 2
L_OBJC_SELECTOR_REFERENCES_5:
.long L_OBJC_METH_VAR_NAME_4
Run Code Online (Sandbox Code Playgroud)
这部分定义了两个局部(就汇编代码而言)'变量'(实际上是标签),L_OBJC_METH_VAR_NAME_4和L_OBJC_SELECTOR_REFERENCES_5.文本.objc_meth_var_names和.objc_message_refs,在"变量"标签之前,告诉汇编器目标文件的哪个部分放置"后面的东西".这些部分对链接器有意义. L_OBJC_SELECTOR_REFERENCES_5最初设置为的地址L_OBJC_METH_VAR_NAME_4.
在执行加载时,在程序开始执行之前,链接器执行大致类似的操作:
.objc_message_refs
部分中的每个条目.0终止C字符串的指针.L_OBJC_METH_VAR_NAME_4包含ASCII C字符串
的地址"constantSelector:test:".sel_registerName("constantSelector:test:")
并存储返回的值
L_OBJC_SELECTOR_REFERENCES_5.知道私有实现细节的链接器可能不会按sel_registerName()字面意思调用.本质上,链接器在加载时为我们的示例执行此操作:
L_OBJC_SELECTOR_REFERENCES_5 = sel_registerName("constantSelector:test:");
Run Code Online (Sandbox Code Playgroud)
这就是"initializer element is not constant"- 初始化元素在编译时必须是常量的原因.在程序开始执行之前,该值实际上是不可知的.即便如此,您的struct声明也存储在不同的链接器.data部分中.链接器只知道如何更新SEL该.objc_message_refs部分中的值,并且无法将该运行时计算的SEL值"复制" .objc_message_refs到其中的某个任意位置.data.
该C源代码...
theSelector = @selector(constantSelector:test:);
Run Code Online (Sandbox Code Playgroud)
......变成:
movl L_OBJC_SELECTOR_REFERENCES_5, %edx // The SEL value the linker placed there.
movl L_theSelector$non_lazy_ptr, %eax // The address of theSelector.
movl %edx, (%eax) // theSelector = L_OBJC_SELECTOR_REFERENCES_5;
Run Code Online (Sandbox Code Playgroud)
由于链接器在程序执行之前完成所有工作,因此L_OBJC_SELECTOR_REFERENCES_5包含与调用时完全相同的值sel_registerName("constantSelector:test:"):
theSelector = sel_registerName("constantSelector:test:");
Run Code Online (Sandbox Code Playgroud)
区别在于这是一个函数调用,如果已经注册了选择器,函数需要执行查找选择器的实际工作,或者完成分配新SEL值以注册选择器的过程.只需加载一个常量值,速度就慢得多.虽然这是"慢",但它确实允许您传递任意C字符串.这在以下情况下非常有用:
sel_registerName()调用之前,才知道选择器.所有选择器都需要通过sel_registerName(),每次只能注册SEL一次.对于任何给定的选择器,这具有在任何地方具有恰好一个值的优点.虽然是一个实现私有细节,但SEL"通常"只是一个char *指向选择器C字符串文本副本的指针.
现在你知道了.知道是成功的一半!
| 归档时间: |
|
| 查看次数: |
1802 次 |
| 最近记录: |