Mar*_*man 23 reflection cocoa objective-c
我想使用objc运行时为Objective-C项目添加脚本支持.现在我面临的问题是,我没有线索,我应该如何调用一个带有几个命名参数的Objective-C方法.
例如,下面的Objective-c调用
[object foo:bar];
Run Code Online (Sandbox Code Playgroud)
可以从C调用:
objc_msgSend(object, sel_getUid("foo:"), bar);
Run Code Online (Sandbox Code Playgroud)
但是我如何为方法调用做类似的事情:
[object foo:var bar:var2 err:errVar];
Run Code Online (Sandbox Code Playgroud)
??
最好的马库斯
Ken*_*Ken 45
接受的答案很接近,但对某些类型无效.例如,如果声明方法将float作为其第二个参数,则这将不起作用.
要正确使用objc_msgSend,必须将其强制转换为适当的类型.例如,如果您的方法声明为
- (void)foo:(id)foo bar:(float)bar err:(NSError **)err
Run Code Online (Sandbox Code Playgroud)
那么你需要做这样的事情:
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);
Run Code Online (Sandbox Code Playgroud)
使用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,它应该用于在某些体系结构上返回某些浮点类型的方法.
现在,既然你正在尝试做一个脚本桥接的事情,你可能无法明确地转换你遇到的每个案例,你想要一个通用的解决方案.总而言之,这并非完全无足轻重,不幸的是,您的代码必须专门针对您希望定位的每个架构(例如i386,x86_64,ppc).你最好的选择可能是看看PyObjC是如何做到的.你还想看看libffi.了解如何在C中传递参数可能是一个好主意,您可以在Mac OS X ABI指南中阅读.最后,在objc运行时工作的Greg Parker 在objc内部编写了一些非常好的帖子.
ken*_*ytm 21
objc_msgSend(object, sel_getUid("foo:bar:err:"), var, var2, errVar);
Run Code Online (Sandbox Code Playgroud)
如果其中一个变量是a float,则需要使用@Ken的方法,或者通过重新解释转换作弊:
objc_msgSend(..., *(int*)&var, ...)
Run Code Online (Sandbox Code Playgroud)
此外,如果选择器返回一个浮点数,您可能需要使用objc_msgSend_fpret,如果它返回一个必须使用的结构objc_msgSend_stret.如果这是对超类的调用,则需要使用objc_msgSendSuper2.
| 归档时间: |
|
| 查看次数: |
18708 次 |
| 最近记录: |