我正在寻找一种使NSInvocation调用特定IMP的方法.默认情况下,它调用可以找到的“最低”IMP(即最近被覆盖的版本),但是我正在寻找一种方法来使它在继承链中从更高层调用IMP.我想要调用的IMP是动态确定的,否则我可以使用超级关键字或类似的东西.
我的想法是使用-forwardInvocation:机制来捕获一个消息(容易且已经工作),然后改变IMP,所以它不会是超级实现也不是最远的后代的实现. (硬)
我发现远程关闭的唯一的事情是AspectObjectiveC,但这需要使用libffi,这使得它与iOS不兼容.理想情况下,我希望这是跨平台.
有任何想法吗?
免责声明:我只是在试验
尝试@ bbum的蹦床功能的想法
所以我觉得我已经有了大部分的事情.我有以下蹦床通过class_addMethod()正确添加,它确实输入:
id dd_trampolineFunction(id self,SEL _cmd,...) { IMP imp = [self retrieveTheProperIMP]; self = [self retrieveTheProperSelfObject]; asm( "jmp %0\n" : : "r" (imp) ); return nil; //to shut up the compiler }
我已经验证了正确的自身和正确的IMP是JMP之前的正确的东西,并且_cmd参数也正确进入. (换句话说,我正确地添加了这个方法).
但是,事情正在发生.我有时会发现自己跳到一个没有自己和_cmd的方法(通常不是正确的).其他时候,我会在一个EXC_BAD_ACCESS的无处中间崩溃.想法? (已经很长时间,因为我已经完成任何程序集…)我在x86_64测试这个.
解决方法
鉴于您已经拥有IMP,您只需要一种方式来对IMP进行一个非常原始的方法调用.鉴于您愿意使用像NSInvocation一样的解决方案,那么您还可以构建类似的代理类.
如果我面对这个,我将创建一个简单的代理类,其中包含要调用的IMP和目标对象(您需要设置自身参数).然后,我将在汇编中编写一个蹦床函数,它接受第一个参数,假设它是代理类的一个实例,抓住自己,将其填充到保存参数0的寄存器中,将IMP和* JMP作为尾部呼叫.
随着蹦床在手,你会添加该蹦床作为任何选择器上的代理类,您希望转发到一个特定的IMP ….
为了实现任何类型的通用机制,关键是避免与重写栈帧有关的任何事情.避免C ABI.避免移动争论.