Подтвердить что ты не робот

Objective-C Указатель выбора для передачи функции C

У меня есть 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.

4b9b3361

Ответ 1

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

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

ИЗМЕНИТЬ 2:

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

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

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

Однако это означает, что вам нужно будет убедиться, что вы добавите указатель на себя в вызов функции 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 определяет частный метод, называемый forward, где отправляются все неизвестные сообщения.

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

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

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

Ответ 2

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

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

Ответ 3

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

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

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

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 блока при освобождении контекста)