使用objc_msgSend通过命名参数调用Objective C函数

我想使用objc运行时为Objective-C项目添加脚本支持。 现在我面对这个问题,我没有线索,我应该如何调用一个带有几个命名参数的Objective-C方法。

所以例如下面的objective-c调用

[object foo:bar]; 

可以从C中调用:

 objc_msgSend(object, sel_getUid("foo:"), bar); 

但是,我将如何为方法调用做类似的事情:

 [object foo:var bar:var2 err:errVar]; 

??

最好的马库斯

 objc_msgSend(object, sel_getUid("foo:bar:err:"), var, var2, errVar); 

如果其中一个variables是float ,则需要使用@Ken的方法,或者通过重新解释来欺骗

 objc_msgSend(..., *(int*)&var, ...) 

此外,如果select器返回一个浮点数,则可能需要使用objc_msgSend_fpret ,如果它返回一个结构,则必须使用objc_msgSend_stret 。 如果这是对超类的调用,则需要使用objc_msgSendSuper2

被接受的答案是接近的,但是对于某些types来说它不能正常工作。 例如,如果该方法被声明为使用float作为其第二个参数,则这将不起作用。

要正确使用objc_msgSend,必须将其转换为适当的types。 例如,如果你的方法被声明为

 - (void)foo:(id)foo bar:(float)bar err:(NSError **)err 

那么你需要做这样的事情:

 void (*objc_msgSendTyped)(id self, SEL _cmd, id foo, float bar, NSError**error) = (void*)objc_msgSend; objc_msgSendTyped(self, @selector(foo:bar:err:), foo, bar, error); 

用objc_msgSend尝试上面的情况,并注销收到的参数。 你不会在被调用的函数中看到正确的值。 这种不寻常的铸造情况出现,因为objc_msgSend不打算被称为像一个正常的C函数。 它是(并且必须)在汇编中实现的,只是在跳过几个寄存器之后跳转到目标C函数。 特别是,在objc_msgSend中没有一致的方法来引用前两个参数。

另一种情况下,直接调用objc_msgSend不会工作是一种方法,返回一个NSRect,比方说,因为objc_msgSend没有在这种情况下使用,objc_msgSend_stret是。 在返回一个NSRect的方法的底层C函数中,第一个参数实际上是一个指向out值NSRect的指针,而函数本身实际上返回void。 调用时必须匹配这个约定,因为这是被调用方法的假设。 此外,使用objc_msgSend_stret的情况在架构上也不相同。 还有一个objc_msgSend_fpret,它应该用于在特定体系结构上返回某些浮点types的方法。

现在,由于您正在尝试执行脚本桥接,所以您可能无法明确地投射您遇到的每个案例,您需要一个通用的解决scheme。 总而言之,这并不是完全微不足道的,不幸的是,您的代码必须专门针对您希望定位的每个架构(例如i386,x86_64,ppc)。 你最好的select可能是看PyObjC是如何做到的 。 你也想看看libffi 。 更多地了解如何在C中传递参数可能是一个好主意,您可以在“ Mac OS X ABI指南”中阅读这些内容。 最后,在objc运行时工作的Greg Parker在objc内部写了一堆很好的post 。

objc_msgSend(obj,@selector(foo:bar:err :),var,var2,&errVar);