用于"id(*IMP)(id,SEL,...)"的第二个参数是什么?

hao*_*hao 1 objective-c gnustep

我的问题就像标题所说的那样.显然,第一个参数用于这个指针,有点像c ++.第二个怎么样?谢谢你

bbu*_*bum 7

签名objc_msgSend()是:

id objc_msgSend(id self, SEL op, ...);
Run Code Online (Sandbox Code Playgroud)

每个方法调用都被编译为对此函数的调用.即,如果你打电话:

[anArray objectAtIndex:42];
Run Code Online (Sandbox Code Playgroud)

这将编译为好像是:

objc_msgSend(anArray, @selector(objectAtIndex:), 42);
Run Code Online (Sandbox Code Playgroud)

现在,对于您的问题,为什么方法会被编译为具有SEL作为第二个参数的函数.或者,更具体地说,为什么这种方法:

- (id)objectAtIndex:(NSUInteger)index;
Run Code Online (Sandbox Code Playgroud)

完全等同于这个C函数:

id object_at_index(id object, SEL _cmd, NSUInteger index);
Run Code Online (Sandbox Code Playgroud)

答案是速度 速度.

速度

具体来说,通过这样做,然后objc_msgSend()永远不必重写堆栈帧*它也可以使用尾调用优化直接跳转到方法调用.这就是为什么你从未objc_msgSend()在调试器中看到回溯的原因(除了你在信使中实际崩溃/中断的时候).

objc_msgSend()使用object_cmd来查找方法的实现,然后,实际上,跳转到该实现.

非常快.堆栈框架未触动过.

并且,正如其他人所说的那样,_cmd出于各种原因,在方法实现中使用可能很方便.同样,它也意味着信使可以通过NSInvocation等进行代理支持等巧妙的技巧.

*重写堆栈帧可能非常复杂和昂贵.有些参数可能会在某些时候出现在寄存器中等等......所有架构都依赖于ABI的肮脏.写东西的最大挑战之一就是在不触及堆栈的情况下imp_implementationWithBlock()弄清楚如何这样做,因为这样做会太慢而且太臃肿而不可行.