理解复杂的块语法

时间:2014-02-27 01:28:06

标签: ios objective-c objective-c-blocks

我是Objective C和iOS开发的初学者,但是13年的.NET资深人士。我很难在心理上绘制以下声明,该声明来自Programming with Objective C指南:

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

它用作为什么应该使用typedef来定义块的示例,但我想了解我正在考虑的内容,以便首先更好地了解块定义语法。

以下是我到目前为止的图表:

enter image description here

我遇到问题的地方是我理解基本语法:

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

如果是这种情况,那么我所拥有的是一个返回void并且没有参数的块,但是名为(^a) (void (^) void)。这意味着我的块的名称,而不是一个直的字符串,本身就是一个块。

显然我在这里遗漏了一些东西。有人可以对此有所了解吗?根据该网站,它简化了这一点:

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

我只是错过了。

编辑:第三个空格应该在括号中。我修好了。它在图像中是错误的,但我不想为此重做整个图像。 :)如果结果是问题的根源,我会在这里修复它。

2 个答案:

答案 0 :(得分:10)

在您的示例中,您错过了第三个​​ void

的一些括号
void (^(^a)(void (^)(void)))(void)

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

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

在此示例中,返回的块不带参数,并返回void

现在让我们建立你的榜样。

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

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

显然typedefs使阅读更容易。

编辑:
考虑这个示例,在第一行中,我使用直观返回语法替换int block

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

我不是百分之百确定我要说的是什么,但我怀疑这种奇怪语法的原因是编译器中的解析器不会混淆。第一个“直观”语法会让编译器认为我们有一个块不带参数返回void ,剩下的字符将被视为语法错误。

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

答案 1 :(得分:0)

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

将这些语法分成几部分:

  1. a是一个变量。
  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)
  7. 所以我们说(^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])
    

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