【问题标题】:Why can't we use C-strings as SELs?为什么我们不能使用 C 字符串作为 SEL?
【发布时间】:2012-06-03 01:52:59
【问题描述】:

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

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 在每一种习惯上都等同于 C 字符串。对包含 @selector(addObject:) 的 SEL 的前 16 个字节进行十六进制转储会得到以下结果:

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

等于 C 字符串 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'***

【问题讨论】:

  • 请注意,您可以使用sel_registerName() 将 C 字符串转换为祝福的 SEL(它基本上在幕后使字符串唯一,以保留后续指针标识)。另请注意,您永远不应直接依赖 SEL 是 char*。它可能永远都是,但这并不能使假设正确。

标签: objective-c methods selector objective-c-runtime


【解决方案1】:

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

【讨论】:

  • 嗯...在查看__sel_registerName 之后,我相信您是正确的。不过,我想知道到底会有多大的性能差异......
  • 字符串/选择器 API 也强烈暗示了这一点;请参阅NSSelectorFromString() 的文档及其与sel_registerName() 的连接。
  • objc_msgSend 这些天运行大约 8 个周期。 strcmp() 没有太多空间;)
猜你喜欢
  • 2013-09-20
  • 1970-01-01
  • 2023-03-17
  • 2021-08-03
  • 2016-12-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多