2012-07-01 31 views
2

如何找出objc_msgSend的结果类型?目的C:objc_msgSend返回类型

从文档:

id objc_msgSend(id theReceiver, SEL theSelector, ...) 

就是一切什么objc_msgSend回报是id型的,对不对?但有时函数返回一个合适的Objective C对象(当要求NSWindow + new时),有时它返回一个bool(这是一个C char)。

如何区分这些不同的结果?我如何知道它是返回对象还是原始类型?

编辑:谢谢你的回复!还有一个问题:是不是至少可以判断返回的类型是原始类型还是适当的对象(并且可能通过object_getClass查询)?

+0

请注意,这种动态通常是要避免的; Objective-C实际上被设计成一个*静态编译的*语言,在运行时*时具有动态多态性。特别是,如果您尝试支持泛型C函数ABI(如果您尝试并支持所有变量的返回值,那么这将是必需的),您将碰到各种各样的地狱。 – bbum

回答

4

如果这是返回类型的运行时发现,则可以使用ObjC运行时API查找给定对象方法的方法定义,然后返回类型。具体方法:

Method class_getInstanceMethod(Class aClass, SEL aSelector)

Method class_getClassMethod(Class aClass, SEL aSelector)

将让你Method结构,您可以随后与

void method_getReturnType(Method method, char *dst, size_t dst_len)

查询来获取CString的说明的返回类型。这个描述不是人类可读的 - 例如,给出你的例子,你会想要检查*dst中引用的字符串是否等于“@”。如果是,则返回类型为id。您可以看到对不同类型编码here的引用,以及我提到的ObjC运行时API方法here

如H 2 CO 3提到的,当从method_getReturnType推断返回类型指示它们的使用是适当的objc_msgSend_fpretobjc_msgSend_stret变体应该被使用(例如,当返回类型将是一个结构或浮动。请参阅ObjC Runtime API文档页面上有关这两种方法的文档说明。)

另外,因为我希望您有美好的一天,所以我觉得我应该警告您运行时代码发现通常有点脆弱,通常是令人讨厌的表现气味。无论如何。 :)

+0

尽管类型编码几乎保证不会改变,但最好(也是为了可读性)与'@encode(some-type)'比较而不是硬编码。 –

+0

对不起,我不太理解:'aClass'和'aSelector'假设'objc_msgSend'的结果是一个有效的对象,不是?如果它返回一个布尔值,我该如何'class_getInstanceMethod'呢? (是的,它是运行时发现) –

+1

Ecir:在这种情况下,您会在调用objc_msgSend之前获得类型编码。在进行调用之前查询有关返回类型的信息,并相应地更改结果数据类型。 –

5

您只能从方法签名中知道它。另外,返回浮点数时,objc_msgSend_fpret以及返回结构时,将使用objc_msgSend_stret

如果返回的值是Objective-C对象,则可以使用​​3210来查询其类。

8

objc_msgSend的调用者应该已经知道返回的类型,并且必须有效地将objc_msgSend转换为返回正确值的函数指针类型。例如,-[NSString UTF8String]将手动调用是这样的:

const char *cStr = ((const char *(*)(id, SEL))objc_msgSend) 
    (@"foo", @selector(UTF8String)); 

是的,太拗口了,这就是为什么它通常是一个更好的主意,让编译器做到这一点。如果您在发送邮件时需要更多活力,我建议首先查看NSInvocation。除此之外,调用初始化的方法签名将包含有关返回类型和所有参数的信息。