Указатель селектора Objective-C для передачи в функцию C - PullRequest
16 голосов
/ 13 августа 2011

У меня есть структура C, которая содержит указатель на функцию.Теперь я использовал эту установку в C без проблем, но теперь я использую эту структуру C в Objective-C, и мне нужно передать указатель на функцию (или селектор), который определен в классе Objective-C.

1.Вот что у меня есть для селектора Objective C, который нужно передать как указатель на функцию C:

- (void)myObjCSelector:(int*)myIntArray
{
    // Do whatever I need with myIntArray
}

2.И вот где я врезаюсь в стену. В Objective-C я пытаюсь передать селектор как указатель на вызов функции C: Вместо " myObjCSelectorPointer "Мне нужен правильный синтаксис для передачи селектора в качестве указателя на функцию в этом вызове функции C:

passObjCSelectorPointerToCContext(cContextReference, myObjCSelectorPointer);

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

Ответы [ 3 ]

18 голосов
/ 13 августа 2011

В объекте селектор не является указателем на функцию. Селектор - это уникальное целое число, которое отображается на строку в таблице поиска методов, хранящейся во время выполнения objc. В приведенном выше случае имя вашего метода будет myObjCSelector:, и чтобы получить уникальный селектор для него, вы наберете @selector(myObjCSelector:). Однако это бесполезно для вас, потому что оно не представляет конкретную реализацию функции.

То, что вы ищете, это IMP. См. этот ТАК вопрос.

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

 IMP myObjCSelectorPointer = (void (*)(id,SEL,int*))[self methodForSelector:@selector(myObjCSelector:)];

Затем вы можете вызвать метод, используя

myObjCSelectorPointer(self,@selector(myObjCSelector:),myIntArray);

Однако это означает, что вам нужно убедиться, что вы добавили указатель на self в вызове функции c passObjCSelectorPointerToCContext. Так должно выглядеть вот так

passObjCSelectorPointerToCContext(cContextReference, self, myObjCSelectorPointer); 

при вызове из объекта, содержащего метод.

Важно отметить, что использование IMP почти никогда не является правильной техникой. Вы должны попытаться придерживаться чистого Obj-C. Obj-C довольно эффективен после первого обращения к сообщению, поскольку использует временное кэширование.

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

Полезно понять, почему objc работает таким образом. В документах Apple подробно объясняется . Однако краткое объяснение таково:

Когда вы отправляете сообщение объекту, например [myobject somemethod], компилятор не сразу узнает, какую конкретную реализацию somemethod вызывать, потому что может быть несколько классов с несколькими переопределенными версиями somemethod. Все эти методы имеют один и тот же селектор, независимо от его аргументов и возвращаемых значений, и, следовательно, решение о том, какая реализация somemethod откладывается при запуске программы. [myobject somemethod] преобразуется компилятором в вызов функции C:

objc_msgSend(myobject, @selector(somemethod))

Это специальная функция, которая ищет каждый макет класса myobject, чтобы узнать, знает ли этот класс, как реагировать на сообщение somemethod. Если нет, то он ищет родителя этого класса и так далее до корня. Если ни один из классов не может ответить на somemethod, тогда NSObject определяет приватный метод, вызываемый вперед, куда отправляются все неизвестные сообщения.

Предполагая, что класс может ответить на сообщение somemethod, он также будет иметь определенный указатель типа IMP, указывающий на фактическую реализацию метода. В этот момент будет вызван метод.

В этой процедуре гораздо больше, чем я описал, но схемы должно быть достаточно, чтобы помочь вам понять, какова цель селектора.

И последнее замечание: имена методов причины сопоставляются с уникальными целыми числами с помощью директивы @selector, чтобы среда выполнения не тратила время на сравнение строк.

1 голос
/ 13 августа 2011

У вас есть для использования указателя функции?В Objective-C вы можете получить указатель функции на реализацию произвольного метода (известного как IMP), но это крайне необычно и, как правило, не очень хорошая идея.Вызов objc_msgSend() напрямую также не самая лучшая идея, потому что есть несколько различных вариантов objc_msgSend(), и компилятор автоматически выбирает для использования разные варианты на основе типа возврата метода.Методы, которые возвращают объект, проходят через objc_msgSend(), но объекты, которые возвращают структуры, могут проходить через objc_msgSend(), или они могут проходить через objc_msgSend_stret().И если метод возвращает double, то он проходит через objc_msgSend_fpret() ...

Документация: Справочник по Objective-C: отправка сообщений

Вместо этого,Я мог бы порекомендовать использовать целевую пару или блок.Тогда вы можете сделать что-то вроде:

myContextRef->target = anObjcObject;
myContextRef->action = @selector(invokeMe:);

А когда закончите, выполните:

[myContextRef->target performSelector:myContextRef->action withObject:someReturnInformation];

Или, возможно, используйте блок:

myContextRef->completionHandler = [^(id returnInformation) {
  [anObjcObject invokeMe:returnInformation];
} copy];

Изатем, когда вы закончите, выполните:

myContextRef->completionHandler(someReturnInformation);

(и не забудьте -release блок, когда вы освободите контекст)

1 голос
/ 13 августа 2011

По сути, ответ таков: селекторы Objective C отличаются от указателей функций. Вам нужно две части данных, чтобы выполнить селектор. Это объект и сам селектор. Для выполнения вашей задачи вам понадобится немного клея.

Отметьте этот вопрос.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...