objective-c - 使用 objc_msgSend 调用带有命名参数的 Objective C 函数

标签 objective-c cocoa reflection

我想使用 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];

??

最好的马库斯

最佳答案

接受的答案很接近,但它对某些类型不能正常工作。例如,如果该方法被声明为将 float 作为它的第二个参数,这将不起作用。

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

- (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 函数那样被调用。它是(而且必须)在汇编中实现的,并且在摆弄几个寄存器后跳转到 Objective-C 函数。特别是, 没有一致的方法来引用 objc_msgSend 中超过前两个参数的任何参数。

另一种直接调用 objc_msgSend 不起作用的情况是返回 NSRect 的方法,因为在这种情况下不使用 objc_msgSend,objc_msgSend_stret 是。在返回 NSRect 的方法的底层 C 函数中,第一个参数实际上是指向输出值 NSRect 的指针,函数本身实际上返回 void。您必须在调用时匹配此约定,因为它是被调用方法将假定的内容。此外,使用 objc_msgSend_stret 的环境因架构而异。还有一个objc_msgSend_fpret,应该用于在某些架构上返回某些浮点类型的方法。

现在,由于您正在尝试做一个脚本桥接的事情,您可能无法显式转换遇到的每个案例,您需要一个通用的解决方案。总而言之,这并非完全微不足道,不幸的是,您的代码必须专门针对您希望定位的每种架构(例如 i386、x86_64、ppc)。你最好的选择可能是看看如何 PyObjC可以。您还想看看 libffi .多了解一下 C 中参数的传递方式可能是个好主意,您可以在 Mac OS X ABI Guide 中阅读相关内容。 .最后,从事 objc 运行时的 Greg Parker 编写了 a bunch of very nice posts关于 objc 内部。

关于objective-c - 使用 objc_msgSend 调用带有命名参数的 Objective C 函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2573805/

相关文章:

c# - C# 中的 using(){...} 与 Cocoa 中的 autoreleasepool{...} 的用途相同吗?

java - 如何在Java中创建通用数组?

ios - 找不到 'UIView' 的接口(interface)声明

objective-c - 如何阻止时间 UILabel 在每次增量时调整大小?

objective-c - 以编程方式更改停靠标题

c# - 没有装箱的通用解析方法

java - 枚举反射

ios - 在 TableView 中分组

iphone - FMDB SQLite 包装器和用户定义/自定义函数

iphone - 为引用的子项目选择构建配置