Objective-C: существует ли-invoke на блоках, который принимает параметры?


Как вы, возможно, знаете, блоки принимают -invoke:

void(^foo)() = ^{
    NSLog(@"Do stuff");
};

[foo invoke];  // Logs 'Do stuff'

Я хотел бы сделать следующее:

void(^bar)(int) = ^(int k) {
     NSLog(@"%d", k);
};

[bar invokeWithParameters:7];   // Want it to log '7', but no such instance method

Обычный аргумент без -invoke работает на bar, но он выводит бессмысленное значение.

Я не могу найти прямое сообщение такого рода, которое я могу отправить блоку, и не могу найти оригинальную документацию, которая описывала бы, как блоки принимают -invoke. Есть ли список сообщений, принятых блоками?

(Да, я пытался использовать class_copyMethodList для извлечения списка методов из время выполнения; кажется, его нет.)

Edit: Да, я также знаю о вызове блока обычным способом (bar(7);). На самом деле мне нужен селектор для метода, который я могу ввести в код библиотеки, который не принимает блоки (per-se).

2 10

2 ответа:

Само определение блока - это сумма "сообщений", которые блок может получить, в терминах вызывающих параметров / ABI.

Это происходит по нескольким причинам:

Во-первых, блок не является функцией, а указатель блока не является указателем функции. Их нельзя использовать взаимозаменяемо.

Во-вторых, C ABI таков, что вы должны иметь объявление функции begin, вызываемой при компиляции сайта вызова, если параметры должны быть закодированы правильно.

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

То есть, если вы не проясните свой вопрос немного, то, что вы просите, либо уже поддерживается, либо почти невозможно из-за капризов C ABI.

Вы можете вызвать его как функцию:

bar(7);

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

Лучшим справочником по поведению блоков является документBlock Language Specification (RTF). Здесь упоминаются некоторые поддерживаемые методы (копирование, сохранение и т. д.) но ничего о методе -invoke.