了解复杂的块语法

我是Objective C和iOS开发的初学者,但是已经有13年的.NET经验。 我很难精神地expression下面的声明,这个声明来自Objective C指南的编程 :

void (^(^a)(void (^) (void))) (void) = ... 

它被用作为什么用typedef来定义块的例子,但是我想了解我在看什么,以便更好地理解块定义语法。

以下是我迄今为止的图表:

在这里输入图像说明

我遇到问题的地方在于,我是如何理解基本语法的:

 [return_val] (^[block_name]) ([block_args]) = ... 

如果是这样的话,那么我所拥有的是一个返回void且没有参数的块,但被命名为(^a) (void (^) void) 。 这意味着我的街区的名字,而不是一个直的string,本身就是一个街区。

很显然,我在这里错过了一些东西。 有人可以请说一说吗? 据网站介绍,这简化到:

 typedef void (^SimpleBlock) (void); SimpleBlock (^complexBlock) (SimpleBlock) = ... 

我只是想念如何。

编辑:第三个空白应该在括号中。 我解决了这个问题 在图像上是错误的,但我不想为此重做整个图像。 :)如果事实certificate是我的问题的来源,我会在这里修复它。

在你的例子中,你错过了第三个 void一些括号

 void (^(^a)(void (^)(void)))(void) 

现在我们来分解一下。 从函数返回块的基本语法是:

 void (^f())(void) { return ^{}; } 

在这个例子中,返回的块没有参数并返回void

现在让我们来构build你的例子。

 void (^myBlock)(void); // Block returning void, taking no args void (^myBlock)(void (^)(void)); // Block returning void, taking block as arg int (^myBlock)(void (^)(void)); // Block returning int, taking block as arg void (^ (^myBlock)(void (^)(void)) )(void); // Block returning block, taking block as arg 

我已经把每一行的中心部分alignment,以便于阅读。 所以困难的部分似乎正在返回一个块。 在最后一行中,我们使用前面描述的语法从函数返回一个块。

显然, typedefs使读起来更容易。

编辑:
考虑这个例子,在第一行中,我用直观的返回语法replace了一个block int

 void (^ )(void) (^myBlock)(void (^)(void)); // Syntax we 'intuitively would use' void (^ (^myBlock)(void (^)(void)) )(void); // Official syntax 

我不是100%确定要说什么,但是我怀疑这个奇怪的语法的原因是为了使编译器中的分析器不会感到困惑。 第一个“直观的”语法会让编译器认为我们有一个没有返回void的参数 ,其余的字符会被认为是语法错误。

在我看来,语法是你不会质疑的东西(当然,你可以批评它),因为它是语言devise的一部分,我们必须遵守规则(由一些希望聪明的工程师设定)代码来编译。

 void (^(^a)(void (^) (void))) (void) 

将这些语法分成几部分:

  1. a是一个variables。
  2. 它可以通过语法“^”像c指针“*”一样取消引用: ^a
  3. (^a)(void (^) (void)是一个名为a的块,并以块(void (^) (void)作为参数。
  4. 它的返回值可以被解引用来产生一个块信息: ^(^a)(void (^) (void)) 。 (并且由此暗示返回值是块指针)
  5. 这个返回的块不带参数: (^(^a)(void (^) (void))) (void)
  6. void (^(^a)(void (^) (void))) (void)

所以我们假设(^a) (void (^) void)不是Meaning the name of my block, rather than being a straight string, is itself a block. 。 块文字不一定是

  [return_val] (^[block_name]) ([block_args]) 

编译器会将插入后的代码作为块。