【问题标题】:Understanding complex block syntax了解复杂的块语法
【发布时间】:2014-02-27 01:28:06
【问题描述】:

我是 Objective C 和 iOS 开发的初学者,但是 13 年的 .NET 老手。我很难在脑海中描绘出以下声明,该声明来自Programming with Objective C 指南:

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

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

这是我到目前为止的图表:

我遇到的问题是我如何理解基本语法:

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

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

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

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

我只是想念如何。

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

【问题讨论】:

  • 你确定void (^(^a)(void (^) void)) (void) 是正确的吗?第三个void不应该在括号中吗?您引用的链接中的哪个 frmm?
  • 你是对的。我会在消息中修复它。也就是说,我认为这不会在物质上改变任何东西,不是吗? (另外,链接在第一段的帖子中。)
  • YouTube 上有相当不错的视频教程。我发现它很有帮助。 youtube.com/watch?v=9FWqh24b9oE
  • Nils Hayat 有一篇非常棒的博文,非常清楚地解释了块语法,从 C 声明符的概念建立起理解。链接:Block Syntax Explained这可能不是一个很好的答案,但这篇博文非常好,我想突出它。
  • 一两个 typedef 可以让代码更易读。

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


【解决方案1】:

在您的示例中,您缺少 第三个​​ 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 使它更易于阅读。

编辑:
考虑这个例子,在第一行中,我用 intuitive 返回语法将int 替换为block

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

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

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

【讨论】:

  • 虽然我理解了这一切,但我想到的问题是为什么最终的语法不像void (^)(void) (^myBlock)(void (^)(void)); 这样第一部分void (^)(void) 是返回值?我认为令人困惑的部分是为什么返回 int 的语法与返回块如此不同。
  • 是的,这就是我遇到的问题。因此,当我阅读时,我将第二个示例视为“一个名为 myBlock 的块,它接受一个未命名的参数,该参数是一个不接受任何参数并返回 void 的块”。因此,阅读最后一行,我看到“一个未命名的块,它接受一个名为 myBlock 的参数,该参数返回一个 void,并采用一个不带参数的未命名块并返回 void,然后返回 void”。这对我来说有点不可思议。不应该是void (^finalBlock(^myBlock)(void (^) (void)))(void)之类的吗?或者这只是我必须适应的事情?
  • 请原谅我,但是带着所有这些括号,我立即被带回了几十年的 LISP。 :-)
【解决方案2】:
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)

假设(^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])

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

【讨论】:

    猜你喜欢
    • 2017-08-01
    • 1970-01-01
    • 2015-09-18
    • 2011-04-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-01-14
    • 2020-08-17
    相关资源
    最近更新 更多