运行performSelector:在一个返回double而不是id的对象上

时间:2011-11-11 00:10:16

标签: objective-c cocoa performselector

如何在对象上运行任意选择器,其返回值为double?例如,我有obj A,它有方法 - (double)blah;

我该怎样做double res = [obj performSelector:@selector(blah)];? performSelector返回一个id类型的对象,所以我应该从id转换为NSInteger加倍 - 这将失去精度?

另外,我想要使用obj的methodSignatureForSelector(意思是,没有NSMethodSignature而没有NSInvocation),因为它是运行时CPU流量很大。

3 个答案:

答案 0 :(得分:7)

您可能需要查看Objective-C运行时函数,尤其是objc_msgSend_fpret

double objc_msgSend_fpret( id self, SEL op, ... )

它将带有浮点返回值的消息发送到类的实例。

performSelector方法使用objc_msgSend,返回id类型。

例如:

double res = objc_msgSend_fpret( obj, @selector( blah ) );

您需要导入此objc运行时标头:

#import <objc/message.h>

修改

顺便说一句,这是ObjC运行时引用的链接: http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/ObjCRuntimeRef/Reference/reference.html

编辑2 - 重要

objc_msgSend_fpret以不同的方式实现,具体取决于CPU架构(基本上是i386或x86_64)。

正如我在评论中所说,这些功能是使用汇编实现的,因此它们的实现取决于CPU架构。

在x86_64架构下,此函数返回long double

这就是当你将它分配给double时失败(并返回NAN)的原因。

另请注意,有一个objc_msgSend_fp2ret函数。

所以,基本上,我之前的例子不起作用:

double x = objc_msgSend_fpret( obj, @selector( blah ) );
printf( "Val: %f\n", x );

正如您所注意到的,它将打印'NAN'。

为了使其有效,你必须这样做:

long double x = objc_msgSend_fpret( obj, @selector( blah ) );
printf( "Val: %Lf\n", x );

这是一个有效的例子:

http://www.eosgarden.com/uploads/misc/fp.m

使用以下方式编译:

gcc -Wall -framework Foundation -o fp fp.m

答案 1 :(得分:6)

如果它是一个没有参数的方法,则可以对该方法返回的值使用valueForKey:doubleValue。否则,我认为你必须使用objc_msgSend_fpret进行捣乱才能使其正常工作。

答案 2 :(得分:3)

使用最少内存(valueForKey:使用两个临时对象),msgSend方法不起作用。

 IMP myImp1 = [obj methodForSelector:@selector(getDouble)];
 double aDouble1 = ((double (*) (id,SEL))myImp1)(obj,@selector(getDouble));