Создание IMP из блока Objective-C - PullRequest
19 голосов
/ 26 ноября 2009

Тип IMP в Objective-C представляет указатель на функцию, насколько я понимаю. Есть ли способ сделать IMP из указателя блока? Спасибо за ваши идеи.

Ответы [ 2 ]

27 голосов
/ 30 ноября 2009

С тех пор, как это было написано, в iOS и Mac OS X теперь есть API, который позволяет напрямую превращать блоки в IMP. Я написал пост в блоге с описанием API (imp_implementationWithBlock ()).

<Ч />

Блок - это, по сути, структура, которая содержит бит метаданных, ссылку на код, содержащийся в блоке, и копию const-скопированных данных, захваченных в блоке.

Таким образом, нет, невозможно напрямую отобразить между IMP и ссылкой на блок.

Когда компилируется вызов блока, компилятор генерирует батут, который устанавливает фрейм стека, а затем переходит к исполняемому коду внутри блока.

Что вы можете сделать, так это создать ИМП, который будет действовать как батут. Для следующего вам понадобится один конкретный IMP для каждого набора аргументов и возвращаемых типов. Если вам нужно сделать этот шаблон, вам нужно использовать ассемблер.

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

(1) Связать блоки, чтобы они действовали как IMP, используя механизм связанных ссылок. Что-то вроде:

void (^implementingBlock)(id s, SEL _c, int v) = ^(id s, SEL _c, int v) {
     // do something here
}

objc_setAssociatedObject(obj, SELToImp, [implementingBlock copy]));

(2) реализовать батутный ИМП примерно так:

void void_id_sel_intTramp(id self, SEL _cmd, int value) {
    int (^block)(id s, SEL _c, int v) = objc_getAssociatedObject(self, _cmd);
    block(self, _cmd, value);
}

(3) добавьте вышеуказанный батут для любого селектора через API среды выполнения Objective C (см. method_setImplementation и т. П.)

Предостережения:

  • это было напечатано в StackOverflow. Реальный код будет похожим, но, вероятно, немного другим.

  • критически важна [копия реализации]; Блоки начинают жизнь в стеке (обычно)

10 голосов
/ 25 сентября 2010

Полагаю, Майк Эш с помощью Лэндона Фуллера решил эту проблему для общего случая, включая iOS, что сложнее. У него есть класс github , который превратит блок в указатель на функцию.

Возможно, вы также захотите сообщить объявление и несколько интересных последующих обсуждений по поводу без какао.

ОБНОВЛЕНИЕ: И теперь есть imp_implementationWithBlock(), как указано выше.

...