Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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.

like image 602
AWF4vk Avatar asked Nov 11 '11 00:11

AWF4vk


Video Answer


2 Answers

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
like image 109
Macmade Avatar answered Sep 23 '22 05:09

Macmade


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.

like image 31
Chuck Avatar answered Sep 20 '22 05:09

Chuck