Существует ли общий непосредственно исполняемый тип для блоков Objective-C?

Я хотел бы избавиться от объявления сложного типа перед моими одноразовыми блоками:

void (^blockHelperA)(NSString*, NSString*) = ^(NSString *foo, NSString *bar) {…};

Это можно было бы переписать как:

id blockHelperB = ^(NSString *foo, NSString *bar) {…};

Что выглядит лучше и компилируется, но не может быть выполнено напрямую:

// “Called object type 'id' is not a function or function pointer”
blockHelperB(@"Foo", @"Bar");

Затем идет тип dispatch_block_t, но это простое сокращение:

typedef void (^dispatch_block_t)(void);

Есть ли способ избавиться от объявления точного типа и по-прежнему выполнять блок простым способом? Я знаю, что могу это сделать:

id foo = ^{ return @"bar"; };
dispatch_sync(dispatch_get_current_queue(), foo);

… но это просто смещает шум от объявления к выполнению.


person zoul    schedule 19.05.2011    source источник
comment
Я нашел эту статью о блоках, которая очень интересна.   -  person Nick Weaver    schedule 19.05.2011
comment
Отличный ресурс о блоках (я его уже читал раньше), но он не отвечает на мой вопрос, по крайней мере, если я ничего не пропустил.   -  person zoul    schedule 19.05.2011
comment
Единственный способ сделать это — сломать систему типов и надеяться, что ничего плохого не произойдет. В частности, вы можете объявить блок, который принимает неизвестное количество аргументов, но единственным соглашением о вызовах, в котором это имеет смысл, является cdecl. И соглашение о вызовах, используемое блоком, может быть или не быть cdecl. Clang, по-видимому, позволяет вам установить это в объявлении, gcc, по-видимому, не позволяет. Просто typedef и покончим с этим.   -  person John Calsbeek    schedule 19.05.2011


Ответы (1)


Не существует (разумного) способа сделать это, поскольку вы ограничены системой типов C.

В частности, для указателей функций и блоков C не позволит вам определить «общий» тип.

Примером этого является то, что тип dispatch_block_t будет только работать с блоками, которые имеют возвращаемый тип void и нулевые аргументы. Другая подпись блока не работает. Период.

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

Дополнительную информацию об этом можно найти здесь: http://clang.llvm.org/docs/Block-ABI-Apple.html.

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

person Jacob Relkin    schedule 19.05.2011
comment
В частности, компилятору необходимо сгенерировать код, устанавливающий стек вызовов и, возможно, память для возвращаемого значения в зависимости от типа возвращаемого значения. - person ; 19.05.2011