Обертывание библиотеки C с помощью Objective-C — указатели функций

Я пишу оболочку для библиотеки C в Objective-C. Библиотека позволяет мне регистрировать функции обратного вызова при возникновении определенных событий.

Функция register_callback_handler() принимает указатель на функцию в качестве одного из параметров.

Мой вопрос к вам, гуру программирования, таков: как я могу представить вызов/селектор метода Objective-C в виде указателя на функцию?

  • Будет ли NSInvocation чем-то полезным в этой ситуации или слишком высоким уровнем?
  • Не лучше ли мне просто написать функцию C, внутри которой записан вызов метода, а затем передать указатель на эту функцию?

Любая помощь будет здорово, спасибо.


person Jasarien    schedule 29.08.2009    source источник


Ответы (1)


Принимает ли register_callback_handler() аргумент контекста (void*)? Большинство API обратного вызова это делают.

Если это так, то вы можете легко использовать NSInvocation. Или вы можете выделить небольшую структуру, содержащую ссылку на объект и селектор, а затем создать свой собственный вызов.

Если он принимает только указатель на функцию, то вы потенциально обделены шлангом. Вам нужно где-то что-то, что однозначно идентифицирует контекст, даже для чистого кодирования C.

Учитывая, что ваш обработчик обратного вызова действительно имеет указатель контекста, все готово:

typedef struct {
    id target;
    SEL selector;
    // you could put more stuff here if you wanted
    id someContextualSensitiveThing;
} TrampolineData;

void trampoline(void *freedata) {
    TrampolineData *trampData = freedata;
    [trampData->target performSelector: trampData->selector withObject: trampData-> someContextualSensitiveThing];
}

...
TrampolineData *td = malloc(sizeof(TrampolineData));
... fill in the struct here ...
register_callback_handler(..., trampoline, td);

Во всяком случае, это общая идея. Если вам нужно иметь дело с аргументами и/или обратными вызовами, не относящимися к объектам, это становится немного сложнее, но не настолько. Самый простой способ — вызвать objc_msgSend() сразу после приведения типа к указателю функции нужного типа, чтобы компилятор сгенерировал правильный сайт вызова (имея в виду, что вам может понадобиться использовать objc_msgSend_stret() для типов возвращаемых структур).

person bbum    schedule 29.08.2009
comment
Я не могу разглашать слишком много информации о библиотеке, мне не разрешено :(. Параметры такие (XFINST inst, unsigned int pid, void *func, void *freedata); Первый - клиентский instancem, второй - идентификатор пакета для конкретного события, третий — указатель на функцию обратного вызова, а последний — указатель на некоторые данные, которые вы, возможно, захотите передать в функцию обратного вызова. - person Jasarien; 30.08.2009
comment
Ну вот... тогда ты золотой. - person bbum; 30.08.2009
comment
Вы имеете в виду, что я могу использовать NSInvocation? - person Jasarien; 30.08.2009
comment
@Jasarien, помните, что void *func (как указано в вашем комментарии) - это pointer to object-type, а не pointer to function-type. В стандарте ничего не говорится о том, допустимо ли преобразование/приведение типов между двумя типами, и, таким образом, неявно неопределенное поведение. Это, вероятно, не проблема для целей objc «лидер рынка», но о чем следует помнить, если вы стремитесь к максимальной мобильности. В любом случае рекомендуется переместить его в правильный аргумент функционального типа. - person johne; 30.08.2009
comment
о, в качестве пояснения к моему комментарию выше - pointer to object-type - это стандартное определение C для «типа объекта» (т. Е. Указатель, который вы получаете от malloc()), а не объект Objective-C. - person johne; 30.08.2009