13

所以,我又一次搞砸了 objc-runtime(出乎意料),我在这里发现了一个有趣的代码块:

const char *sel_getName(SEL sel) {
#if SUPPORT_IGNORED_SELECTOR_CONSTANT
    if ((uintptr_t)sel == kIgnore) return "<ignored selector>";
#endif
    return sel ? (const char *)sel : "<null selector>";
}

所以,这告诉我的是SEL,在每一种习惯上,a 都等同于 C 弦。对包含的 SEL 的前 16 个字节进行十六进制转储@selector(addObject:)会得到以下结果:

61 64 64 4F 62 6A 65 63 74 3A 00 00 00 00 00 00

这等于 C-string addObject:

话虽如此,当我使用 C 字符串作为选择器时,为什么这段代码会崩溃?

SEL normalSEL  = @selector(addObject:);
SEL cStringSEL = (SEL) "addObject:";

NSMutableArray *arr = [NSMutableArray arrayWithObjects:@"1", @"2", nil];

[arr performSelector:normalSEL withObject:@"3"];
[arr performSelector:cStringSEL withObject:@"4"];

NSLog(@"%@", arr);

据我所知,选择器的内容是相同的,那么为什么第二个选择器崩溃并显示以下错误消息?

***由于未捕获的异常“NSInvalidArgumentException”而终止应用程序,原因:“-[__NSArrayM addObject:]:无法识别的选择器发送到实例 0x101918720”***

4

1 回答 1

22

选择器是内部的 C 字符串,并通过它们的地址而不是它们的内容进行比较。字符串内容仅用于转换为/从外部字符串表示。实习是为了提高性能——当运行时查找与选择器匹配的方法实现时,它可以直接比较选择器指针,而不是取消引用每个指针并比较字符。

于 2012-05-28T18:38:32.950 回答