我在一个个人项目中使用了 Objective-C++,我发现SEL
在全局范围内带有初始化程序的变量有奇怪的行为。考虑这个可运行的 Objective-C++ 片段:
#import <Foundation/Foundation.h>
@interface Foo : NSObject
-(void)closeWindow;
@end
@implementation Foo
-(void)closeWindow { puts("closeWindow called"); }
@end
static SEL globalSelector = @selector(closeWindow);
void printSelectorInfo(id target, SEL sel) {
const char* name = sel_getName(sel);
BOOL responds = [target respondsToSelector:sel];
printf("selector=%p; name=%s; responds=%hhu\n", sel, name, responds);
}
int main(int argc, const char * argv[]) {
@autoreleasepool {
SEL localSelector = @selector(closeWindow);
Foo* foo = [[Foo alloc] init];
printSelectorInfo(foo, localSelector);
printSelectorInfo(foo, globalSelector);
[foo closeWindow];
[foo performSelector:localSelector];
[foo performSelector:globalSelector];
}
}
在普通的 Objective-C 中,全局变量必须具有 C 规定的常量初始化器,因此static SEL globalSelector = @selector(closeWindow)
无效。这个限制在 C++ 中被取消,因此在 Objective-C++ 中,它可以毫无问题地编译。
这将是预期的输出:
选择器=<某个地址>; 名称=关闭窗口;响应=1
选择器=<某个地址>;名称=关闭窗口;响应=1
closeWindow 调用 [3 次]
这确实是我在调试中得到的:
selector=0x7fff952d63a1; name=closeWindow; responds=1
selector=0x7fff952d63a1; name=closeWindow; responds=1
closeWindow called
closeWindow called
closeWindow called
但是,Release 中出现了问题:
selector=0x7fff952d63a1; name=closeWindow; responds=1
selector=0x100000eca; name=closeWindow; responds=0
closeWindow called
closeWindow called
2013-05-06 16:40:11.960 selectors[5048:303] *** NSForwarding: warning: selector (0x100000eca) for message 'closeWindow' does not match selector known to Objective C runtime (0x7fff952d63a1)-- abort
2013-05-06 16:40:11.964 selectors[5048:303] -[Foo closeWindow]: unrecognized selector sent to instance 0x100108240
2013-05-06 16:40:11.966 selectors[5048:303] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[Foo closeWindow]: unrecognized selector sent to instance 0x100108240'
*** First throw call stack:
(
0 CoreFoundation 0x00007fff91116b06 __exceptionPreprocess + 198
1 libobjc.A.dylib 0x00007fff904843f0 objc_exception_throw + 43
2 CoreFoundation 0x00007fff911ad40a -[NSObject(NSObject) doesNotRecognizeSelector:] + 186
3 CoreFoundation 0x00007fff9110502e ___forwarding___ + 414
4 CoreFoundation 0x00007fff91104e18 _CF_forwarding_prep_0 + 232
5 selectors 0x0000000100000e14 main + 234
6 libdyld.dylib 0x00007fff944a77e1 start + 0
7 ??? 0x0000000000000001 0x0 + 1
)
libc++abi.dylib: terminate called throwing an exception
请注意,虽然它们仍然具有相同的名称,但选择器没有相同的地址,并且Foo
只响应局部变量中的选择器。
有趣的是,这个问题似乎与名称有关。如果我将方法的名称更改为,例如foo
,它可以正常工作。
我是否缺少某些东西或依赖未定义的行为?