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

Dav*_*vid 4 cocoa objective-c performselector

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

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

另外,我希望使用的obj的methodSignatureForSelector(意思是,没有NSMethodSignature,没有NSInvocation),因为它是在运行时一个巨大的CPU消耗.

Mac*_*ade 7

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

double objc_msgSend_fpret( id self, SEL op, ... )
Run Code Online (Sandbox Code Playgroud)

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

performSelector方法使用objc_msgSend,它返回一个id类型.

例如:

double res = objc_msgSend_fpret( obj, @selector( blah ) );
Run Code Online (Sandbox Code Playgroud)

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

#import <objc/message.h>
Run Code Online (Sandbox Code Playgroud)

编辑

顺便说一下,这里是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.

这就是为什么当你将它分配给a时失败(并返回NAN)double.

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

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

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

如你所知,它将打印'NAN'.

为了使它工作,你必须这样做:

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

这是一个有效的例子:

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

使用以下方法编译它:

gcc -Wall -framework Foundation -o fp fp.m
Run Code Online (Sandbox Code Playgroud)


Chu*_*uck 6

如果它是一个没有参数的方法,则可以使用valueForKey:doubleValue从该方法返回的值.否则,我认为你必须捣乱objc_msgSend_fpret才能使其发挥作用.


Dav*_*vid 4

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

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