Running performSelector: on an object that returns a double, not id

£可爱£侵袭症+ 提交于 2021-02-07 14:40:40

问题


How can I run an arbitrary selector on an object, the return of which is a double? For example, I have obj A, which has method -(double)blah;

How can I do double res = [obj performSelector:@selector(blah)];? performSelector returns an id type object, so should I cast from id to NSInteger to double - that will lose precision?

Also, I do not want to use the obj's methodSignatureForSelector (meaning, no NSMethodSignature and no NSInvocation) because it is a huge CPU drain at run-time.


回答1:


You may want to take a look at the Objective-C runtime functions, especially objc_msgSend_fpret.

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

Which sends a message with a floating-point return value to an instance of a class.

The performSelector methods use objc_msgSend, which returns an id type.

For instance:

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

You'll need to import this objc runtime header:

#import <objc/message.h>

EDIT

By the way, here's the link to the ObjC runtime reference: http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/ObjCRuntimeRef/Reference/reference.html

EDIT 2 - IMPORTANT

objc_msgSend_fpret is implemented in different ways, depending on the CPU architecture (basically, i386 or x86_64).

As I said in a comment, those functions are implemented using assembly, so their implementations depends on the CPU architecture.

Under the x86_64 architecture, this function returns a long double.

This is why it fails (and returning NAN) when you assign it to a double.

Also note that there is an objc_msgSend_fp2ret function.

So, basically, my previous example will not work:

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

As you noticed, it will print 'NAN'.

To make it work, you'll have to do it this way:

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

Here's a working example:

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

Compile it using:

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



回答2:


If it's a method with no arguments, you can use valueForKey: and doubleValue on the value returned from that method. Otherwise, I think you'll have to muck with objc_msgSend_fpret to make it work.




回答3:


Uses least memory (valueForKey: uses two temporary objects) and the msgSend method doesn't work.

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


来源:https://stackoverflow.com/questions/8088145/running-performselector-on-an-object-that-returns-a-double-not-id

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!