Как правило, для обратного вызова в Objective-C требуются две части информации; вызываемый метод и объект для его вызова. Ни просто селектор, ни просто IMP - результат instanceMethodForSelector:
- не будет достаточной информацией.
Большинство API обратного вызова предоставляют указатель контекста, который обрабатывается как непрозрачное значение, которое передается через Перезвоните. Это ключ к вашей загадке.
То есть, если у вас есть функция обратного вызова, объявленная как:
typedef void (*CallBackFuncType)(int something, char *else, void *context);
И некоторый API, который использует указатель указанного типа функции обратного вызова:
void APIThatWillCallBack(int f1, int f2, CallBackFuncType callback, void *context);
Тогда вы бы реализовали свой обратный вызов примерно как это:
void MyCallbackDude(int a, char *b, void *context) {
[((MyCallbackObjectClass*)context) myMethodThatTakesSomething: a else: b];
}
И затем вы могли бы назвать API чем-то вроде этого:
MyCallbackObjectClass *callbackContext = [MyCallbackObjectClass new];
APIThatWillCallBack(17, 42, MyCallbackDude, (void*)callbackContext);
Если вам нужно переключаться между разными селекторами, Я бы рекомендовал создать небольшой связующий класс, который находится между обратным вызовом и API Objective-C. Экземпляр связующего класса может содержать необходимую конфигурацию или логику, необходимую для переключения между селекторами на основе входящих данных обратного вызова.
Вы можете создать класс C ++ как оболочку. И вызовите сообщение цели C из этого класса. Просто не забудьте сделать свой файл yoursource.mm вместо yoursource.cpp .
Вы можете сделать это с помощью instanceMethodForSelector:
Дополнительную информацию см. В документации Apple NSObject .
Вы можете сделать это с помощью @selector
и типа SEL
:
SEL sel = @selector(myMethod:);
/* Equivalent to [someObject myMethod:Paramater] */
[someObject performSelector:sel withObject:Parameter]
Существует также тип IMP
. ..
IMP imp = [someObject methodForSelector:sel];
/* don't remember if this syntax is correct; it's been a while...
* the idea is that it's like a function pointer. */
imp(someObject, sel, Parameter);
Обновление на основе ваших комментариев
Если вы не хотите указывать объект, в этом случае вы просите что-то ужасно непереносимое. По сути, вам нужны лямбда-выражения, которые не являются особенностью C, хотя они входят в C ++ 0x.
Так что мое решение будет «незаметным», схематичным и непереносимым ...
НО. .. возможно, вы сможете сделать это с помощью генерации кода времени выполнения ...
Вы можете начать с написания функции-заглушки в ассемблере (при условии, что вам нужен x86)
push dword 0 ; SEL will go here
push dword 0 ; Object will go here
push dword 0 ; IMP will go here
pop eax ; eax = imp
call eax ; call imp
add esp, 8 ; cleanup stack
ret ; return
Это собирается в:
0068 0000 6800 0000 0000 0068 0000 5800 d0ff c481 0004 0000 00c3
Обратите внимание на инструкцию push dword 0
- это байты 68 00 00 00 00
. Мы будем вводить нули в указатель во время выполнения.
Итак, мы можем скопировать это в буфер malloc ()
d, исправить его и вызвать mprotect ()
, чтобы сделать его исполняемым.
Код ниже предназначен для иллюстративных целей, а я понятия не имею, работает ли это. : -)
/* x86 code... */
char code[] = { 0x68, 0x00, 0x00, 0x00, 0x00, 0x68,
0x00, 0x00, 0x00, 0x00, 0x68, 0x00,
0x00, 0x00, 0x00, 0x58, 0xff, 0xd0,
0x81, 0xc4, 0x04, 0x00, 0x00, 0x00,
0xc3 };
char *buf = malloc(sizeof(code));
SEL Selector = @selector(Method);
IMP Imp = [object methodForSelector:Selector];
/* Copy template */
memcpy(buf, code, sizeof(code));
/* Patch the "push dword 0" parts with your arguments
* This assumes everything is 32-bit, including SEL, IMP, etc. */
memcpy(buf + 1, &Selector, sizeof(Selector));
memcpy(buf + 6, &object, sizeof(object));
memcpy(buf + 11, &Imp, sizeof(Imp));
/* Now here comes the sketchy part...
* Make it executable and turn it into a function pointer. */
mprotect(buf, sizeof(code), PROT_EXEC);
void (*Function)() = (void(*)())buf;
/* Now, crazy as it sounds, you should be able to do: */
Function();
Возможно, вы захотите сделать [сохранение объекта]
до тех пор, пока существует эта функция, и [освобождение объекта]
, когда и если вы захотите освободить его . (Возможно, лучше всего обернуть эту эскизность внутри объекта, а затем использовать обычный счет ссылок objc для управления буфером и ссылку на объект
.) Возможно, вы также захотите использовать mmap ()
выделить вместо malloc ()
...
Если это звучит излишне сложно, это потому, что это так. : -)
и вызовите mprotect ()
, чтобы сделать его исполняемым.
Код ниже предназначен для иллюстративных целей, и я не знаю, работает ли он. : -)
/* x86 code... */
char code[] = { 0x68, 0x00, 0x00, 0x00, 0x00, 0x68,
0x00, 0x00, 0x00, 0x00, 0x68, 0x00,
0x00, 0x00, 0x00, 0x58, 0xff, 0xd0,
0x81, 0xc4, 0x04, 0x00, 0x00, 0x00,
0xc3 };
char *buf = malloc(sizeof(code));
SEL Selector = @selector(Method);
IMP Imp = [object methodForSelector:Selector];
/* Copy template */
memcpy(buf, code, sizeof(code));
/* Patch the "push dword 0" parts with your arguments
* This assumes everything is 32-bit, including SEL, IMP, etc. */
memcpy(buf + 1, &Selector, sizeof(Selector));
memcpy(buf + 6, &object, sizeof(object));
memcpy(buf + 11, &Imp, sizeof(Imp));
/* Now here comes the sketchy part...
* Make it executable and turn it into a function pointer. */
mprotect(buf, sizeof(code), PROT_EXEC);
void (*Function)() = (void(*)())buf;
/* Now, crazy as it sounds, you should be able to do: */
Function();
Возможно, вы захотите сделать [сохранение объекта]
, пока существует эта функция, и [освобождение объекта]
, когда и если вам следует освободить его . (Вероятно, лучше всего обернуть эту эскизность внутри объекта, а затем использовать обычный счет ссылок objc для управления буфером и ссылку на объект
.) Возможно, вы также захотите использовать mmap ()
выделить вместо malloc ()
...
Если это звучит излишне сложно, это потому, что это так. : -)
и вызовите mprotect ()
, чтобы сделать его исполняемым.
Код ниже предназначен для иллюстративных целей, и я не знаю, работает ли он. : -)
/* x86 code... */
char code[] = { 0x68, 0x00, 0x00, 0x00, 0x00, 0x68,
0x00, 0x00, 0x00, 0x00, 0x68, 0x00,
0x00, 0x00, 0x00, 0x58, 0xff, 0xd0,
0x81, 0xc4, 0x04, 0x00, 0x00, 0x00,
0xc3 };
char *buf = malloc(sizeof(code));
SEL Selector = @selector(Method);
IMP Imp = [object methodForSelector:Selector];
/* Copy template */
memcpy(buf, code, sizeof(code));
/* Patch the "push dword 0" parts with your arguments
* This assumes everything is 32-bit, including SEL, IMP, etc. */
memcpy(buf + 1, &Selector, sizeof(Selector));
memcpy(buf + 6, &object, sizeof(object));
memcpy(buf + 11, &Imp, sizeof(Imp));
/* Now here comes the sketchy part...
* Make it executable and turn it into a function pointer. */
mprotect(buf, sizeof(code), PROT_EXEC);
void (*Function)() = (void(*)())buf;
/* Now, crazy as it sounds, you should be able to do: */
Function();
Возможно, вы захотите сделать [сохранение объекта]
до тех пор, пока существует эта функция, и [освобождение объекта]
, когда и если вы захотите освободить его . (Возможно, лучше всего обернуть эту эскизность внутри объекта, а затем использовать обычный счет ссылок objc для управления буфером и ссылку на объект
.) Возможно, вы также захотите использовать mmap ()
выделить вместо malloc ()
...
Если это звучит излишне сложно, это потому, что это так. : -)
-)/* x86 code... */
char code[] = { 0x68, 0x00, 0x00, 0x00, 0x00, 0x68,
0x00, 0x00, 0x00, 0x00, 0x68, 0x00,
0x00, 0x00, 0x00, 0x58, 0xff, 0xd0,
0x81, 0xc4, 0x04, 0x00, 0x00, 0x00,
0xc3 };
char *buf = malloc(sizeof(code));
SEL Selector = @selector(Method);
IMP Imp = [object methodForSelector:Selector];
/* Copy template */
memcpy(buf, code, sizeof(code));
/* Patch the "push dword 0" parts with your arguments
* This assumes everything is 32-bit, including SEL, IMP, etc. */
memcpy(buf + 1, &Selector, sizeof(Selector));
memcpy(buf + 6, &object, sizeof(object));
memcpy(buf + 11, &Imp, sizeof(Imp));
/* Now here comes the sketchy part...
* Make it executable and turn it into a function pointer. */
mprotect(buf, sizeof(code), PROT_EXEC);
void (*Function)() = (void(*)())buf;
/* Now, crazy as it sounds, you should be able to do: */
Function();
Возможно, вы захотите сделать [сохранение объекта]
, пока существует эта функция, и [освобождение объекта]
, когда и если вы должны выбрать его освобождение. (Вероятно, лучше всего обернуть эту эскизность внутри объекта, а затем использовать обычный счет ссылок objc для управления буфером и ссылку на объект
.) Возможно, вы также захотите использовать mmap ()
выделить вместо malloc ()
...
Если это звучит излишне сложно, это потому, что это так. : -)
-)/* x86 code... */
char code[] = { 0x68, 0x00, 0x00, 0x00, 0x00, 0x68,
0x00, 0x00, 0x00, 0x00, 0x68, 0x00,
0x00, 0x00, 0x00, 0x58, 0xff, 0xd0,
0x81, 0xc4, 0x04, 0x00, 0x00, 0x00,
0xc3 };
char *buf = malloc(sizeof(code));
SEL Selector = @selector(Method);
IMP Imp = [object methodForSelector:Selector];
/* Copy template */
memcpy(buf, code, sizeof(code));
/* Patch the "push dword 0" parts with your arguments
* This assumes everything is 32-bit, including SEL, IMP, etc. */
memcpy(buf + 1, &Selector, sizeof(Selector));
memcpy(buf + 6, &object, sizeof(object));
memcpy(buf + 11, &Imp, sizeof(Imp));
/* Now here comes the sketchy part...
* Make it executable and turn it into a function pointer. */
mprotect(buf, sizeof(code), PROT_EXEC);
void (*Function)() = (void(*)())buf;
/* Now, crazy as it sounds, you should be able to do: */
Function();
Возможно, вы захотите сделать [сохранение объекта]
, пока существует эта функция, и [освобождение объекта]
, когда и если вы должны выбрать его освобождение. (Вероятно, лучше всего обернуть эту эскизность внутри объекта, а затем использовать обычный счет ссылок objc для управления буфером и ссылку на объект
.) Возможно, вы также захотите использовать mmap ()
выделить вместо malloc ()
...
Если это звучит излишне сложно, это потому, что это так. : -)
Я также захочу использовать mmap ()
для выделения вместо malloc ()
...
Если это звучит излишне сложно, это потому, что это так. : -)
Я также захочу использовать mmap ()
для выделения вместо malloc ()
...
Если это звучит излишне сложно, это потому, что это так. : -)