Есть ли способ обернуть блок ObjectiveC в указатель функций?

Я должен предоставить обратный вызов C-стиля для конкретной библиотеки C в приложении iOS. Обратный вызов не имеет void *userData или что-то подобное. Поэтому я не могу зацикливаться в контексте. Я бы хотел избежать глобального контекста, чтобы решить эту проблему. Идеальным решением будет блок Objective-C.

Мой вопрос: есть ли способ «бросить» блок в указатель функции или каким-то образом обернуть / скрыть его?

4 Solutions collect form web for “Есть ли способ обернуть блок ObjectiveC в указатель функций?”

Технически вы можете получить доступ к указателю на функцию для блока. Но это абсолютно небезопасно, поэтому я, конечно, не рекомендую. Чтобы узнать, как, рассмотрим следующий пример:

 #import <Foundation/Foundation.h> struct Block_layout { void *isa; int flags; int reserved; void (*invoke)(void *, ...); struct Block_descriptor *descriptor; }; int main(int argc, char *argv[]) { @autoreleasepool { // Block that doesn't take or return anything void(^block)() = ^{ NSLog(@"Howdy %i", argc); }; // Cast to a struct with the same memory layout struct Block_layout *blockStr = (struct Block_layout *)(__bridge void *)block; // Now do same as `block()': blockStr->invoke(blockStr); // Block that takes an int and returns an int int(^returnBlock)(int) = ^int(int a){ return a; }; // Cast to a struct with the same memory layout struct Block_layout *blockStr2 = (struct Block_layout *)(__bridge void *)returnBlock; // Now do same as `returnBlock(argc)': int ret = ((int(*)(void*, int a, ...))(blockStr2->invoke))(blockStr2, argc); NSLog(@"ret = %i", ret); } } 

Выполнение этого дает:

 Howdy 1 ret = 1 

Это то, чего мы ожидаем от чисто выполнения этих блоков непосредственно с помощью block() . Таким образом, вы можете использовать invoke качестве указателя на функцию.

Но, как я уже сказал, это абсолютно небезопасно. На самом деле не используйте это!

Если вы хотите просмотреть рецензию о том, как сделать то, что вы просите, тогда проверьте это: http://www.mikeash.com/pyblog/friday-qa-2010-02-12-trampolining-blocks -с-изменяемые-code.html

Это просто отличная рецензия на то, что вам нужно сделать, чтобы заставить это работать. К сожалению, он никогда не будет работать на iOS (так как вам нужно пометить страницу как исполняемую, которую вы не можете делать в песочнице вашего приложения). Но, тем не менее, отличная статья.

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

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

MABlockClosure может сделать именно это. Но это может быть излишним для всего, что вам нужно.

Описание imp_implementationWithBlock (найденное в objc/runtime.h ) имеет следующее:

Создает указатель на функцию, которая вызывается блоком при вызове метода.

Предполагается, что он используется для методов, но, похоже, вы можете использовать его для преобразования любого (см. Комментарии ниже в newacct) блока в указатель функции:

 #import <Foundation/Foundation.h> #import <objc/runtime.h> int main(int argc, const char * argv[]) { @autoreleasepool { NSString *message = @"Hello, World!"; NSString* (^upperCaseStringBlock)(NSString*) = ^NSString*(NSString* string) { return [string uppercaseString]; }; NSString* (*upperCaseString)(NSString*) = (void*)imp_implementationWithBlock(upperCaseStringBlock); NSString *upperCaseMessage = upperCaseString(message); NSLog(@"%@", upperCaseMessage); // Probably optional imp_removeBlock((IMP)upperCaseString); } return 0; } 
  • Передача данных между двумя контроллерами представления с использованием «Делегация»: Objective-C
  • Неисправность записи функции обратного вызова рендеринга удаленного ввода-вывода
  • Несколько делегатов в iOS
  • iOS: ShareKit >> Настройки Twitter >> Обратный звонок - что это такое?
  • Как обратный вызов C возвращает объект Objective-C с помощью указателя userdata?
  • не удалось получить обратный вызов со второго контроллера
  • Прием вызовов CFSocket не вызывается. Что я пропустил?
  • Прерывистый сбой в записиCallback () при запуске приложения
  • iOS: сохранение и запуск блока обратного вызова
  • обратный вызов обратной кнопки в navigationController в iOS
  • Как создать callBack в iOS, который должен вызываться библиотекой
  • PhoneC: Разработка iOS проста с помощью XCode, Swift3, UITableView, cocatouch, давайте создадим приложения для iPhone, iPad и Macbook.