Выполнение executeSelector: для объекта, который возвращает double, а не id - PullRequest
4 голосов
/ 11 ноября 2011

Как я могу запустить произвольный селектор на объекте, возвращаемое значение которого удваивается? Например, у меня есть объект A, который имеет метод - (двойной) бла;

Как я могу сделать double res = [obj performSelector:@selector(blah)];? executeSelector возвращает объект типа id, так что я должен привести от id к NSInteger к удвоению - что потеряет точность?

Кроме того, я не хочу использовать объект methodSignatureForSelector (имеется в виду, нет NSMethodSignature и нет NSInvocation), потому что во время выполнения это огромная утечка ЦП.

Ответы [ 3 ]

7 голосов
/ 11 ноября 2011

Возможно, вы захотите взглянуть на функции времени выполнения 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 ) );

Вам потребуется импортировать этот объектзаголовок времени выполнения:

#import <objc/message.h>

РЕДАКТИРОВАТЬ

Кстати, вот ссылка на ссылку времени выполнения ObjC: http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/ObjCRuntimeRef/Reference/reference.html

РЕДАКТИРОВАНИЕ 2 - ВАЖНО

objc_msgSend_fpret реализовано по-разному, в зависимости от архитектуры процессора (в основном, i386 или x86_64).

Как я уже сказал в комментарии, эти функцииреализованы с использованием ассемблера, поэтому их реализация зависит от архитектуры ЦП.

В архитектуре x86_64 эта функция возвращает long double.

Именно поэтому она завершается с ошибкой (и возвращает NAN), когдаВы назначаете его на double.

Также обратите внимание, что есть функция objc_msgSend_fp2reton.

Так что, в принципе, мой предыдущий пример не будет работать:

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
6 голосов
/ 11 ноября 2011

Если это метод без аргументов, вы можете использовать valueForKey: и doubleValue для значения, возвращаемого этим методом.В противном случае, я думаю, вам придется гадить с objc_msgSend_fpret, чтобы все заработало.

3 голосов
/ 11 ноября 2011

Использует минимум памяти (valueForKey: использует два временных объекта), а метод msgSend не работает.

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