Синтаксис для определения блока, который принимает блок и возвращает блок в Objective-C
Я нахожу в документе Apple , работающем с блоками , что синтаксис для определения блока, который возвращает результат умножения двух значений:
double (^multiplyTwoValues)(double, double);
Отличается от определения блока, который принимает другой блок в качестве аргумента и возвращает еще один блок:
void (^(^complexBlock)(void (^)(void)))(void);
Почему второй синтаксис не void (^)(void)(^complexBlock)(void (^)(void))
?
2 ответа:
Именно так работает синтаксис языка Си. Синтаксис блока основан на указателях функций , что сводится к идее Денниса Ричи о том, что "объявление вещи должно выглядеть как использование этой вещи".
Если бы вы использовали" сложный блок", который вы определили, а затем также вызывали возвращаемый блок в той же строке, это выглядело бы так:
complexBlock(void (^argBlock)(void){ /*...*/ })(); // ^ Argument (a literal Block) to the main Block // ^ Invocation of the returned Block
Далее, разбор c-деклараций следует так называемому"правому-левому правилу". Первый шаг это "найти идентификатор". Для вашего заявления это
complexBlock
.Затем посмотрите направо. Мы попали в закрывающую скобку, так что это конец объявления "единица".void (^(^complexBlock)(void (^)(void)))(void); // | ! | Found identifier: "complexBlock is..."
void (^(^ )(void (^)(void)))(void); // | ! Right parenthesis closes a part of the declaration
Вернитесь к началу текущей части и читайте слева, пока не появится открывающая скобка. Мы находим каретку, указывающую на тип блока. Продолжайте читать слева и найдите открывающую скобку, закрывающую эту часть объявления.
void (^(^ (void (^)(void)))(void); // |! | "...a Block..."
Затем снова направо. Здесь мы находим отверстие скобка, указывающая начало списка параметров. Пропустите список параметров, поскольку вас интересует тип возвращаемого значения, но он анализируется как отдельное объявление.
void (^ (void (^)(void)))(void); // | ! | "...taking something or other and returning..."
Теперь, когда мы использовали список параметров:
void (^ )(void); // | |
Продолжайте двигаться вправо, и мы попадем в закрывающую скобку:
void (^ )(void); // | !
Итак, снова вернемся к началу текущей части и двинемся влево, где мы найдем каретку блока.
void (^ (void); // ! | "...a Block.."
Вот ключевая часть для вашего вопрос об этой декларации:
Двигаясь влево, мы снова находим открывающую скобку, поэтому мы возвращаемся к движению вправо. Вот почему список параметров возвращаемого блока идет в конце объявления.Пройдя через все это, остальное должно быть самоочевидным. Кстати, на странице, на которую я ссылался, есть несколько демонстраций, подобных моей, одна из которых включает в себя указатели функций. Вы также можете быть удивлены http://cdecl.org , которая представляет собой онлайн-реализацию программы, которая анализирует объявления C и может помочь вам понять более тонкие разновидности.void ( (void); // ! | Left parenthesis closes part of declaration, // **now move rightwards again**
Синтаксис блока Obj-C довольно сложен для чтения, его можно немного упростить с помощью typedefs.
//setup typedef void (^ReturnedBlock)(void); ReturnedBlock retBlock = ^void(void){}; typedef void (^ParamBlock)(void); ParamBlock paramBlock = ^void(void){}; //the thing you want to do ReturnedBlock (^someBlock)(ParamBlock) = ^ReturnedBlock(ParamBlock param){ return retBlock; }; //perform the block ReturnedBlock r = someBlock(paramBlock);