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

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

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");

Тогда theres a dispatch_block_t, но это просто сокращенная строка:

typedef void (^dispatch_block_t)(void);

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

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

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

Ответы

Ответ 1

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

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

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

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

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

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