【问题标题】:Syntax to define a Block that takes a Block and returns a Block in Objective-C在 Objective-C 中定义一个 Block 并返回一个 Block 的语法
【发布时间】:2014-11-27 03:22:55
【问题描述】:

我在 Apple 的文档 Working with Blocks 中找到了定义返回两个值相乘结果的块的语法:

double (^multiplyTwoValues)(double, double);

不同于定义一个将另一个块作为参数并返回另一个块的块:

void (^(^complexBlock)(void (^)(void)))(void);

为什么第二个语法不是void (^)(void)(^complexBlock)(void (^)(void))

【问题讨论】:

  • “为什么第二个语法不是...”因为块语法需要与已有 45 年历史的 C 语言的其余部分相适应,并且每个人都希望语法是这样的。 Swift 有更好的块语法,如果你不喜欢 Objective-C 的语法,可以使用它。

标签: objective-c syntax objective-c-blocks declaration


【解决方案1】:

这就是 C 语法的工作原理。 Block 语法基于 function pointers 的语法,这归结为 Dennis Ritchie 的想法,即“事物的声明应该看起来像对该事物的使用”。

如果你要使用你定义的“复杂块”,然后在同一行中调用返回的块,它看起来像这样:

complexBlock(void (^argBlock)(void){ /*...*/ })();
//           ^ Argument (a literal Block) to the main Block
//                                              ^ Invocation of the returned Block

此外,C 声明的解析遵循所谓的"right-left rule"。第一步是“找到标识符”。对于你的声明,那是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.."

以下是您关于此声明的问题的关键部分:

向左移动,我们再次找到一个左括号,所以我们返回向右移动。这就是为什么 return Block 的参数列表放在声明的末尾。

void (                                (void);
//   !                               | Left parenthesis closes part of declaration,
//                                     **now move rightwards again**

经历了所有这些,其余的应该是不言而喻的。

顺便说一下,我链接到的关于左右规则的页面有一些和我一样的演示,其中一个涉及函数指针。您可能还会对http://cdecl.org 感兴趣,这是一个在线实现的程序,可以解析 C 声明,可以帮助您了解更羊毛的品种。

【讨论】:

  • 解释的很详细,解开了很多Objective C 块的疑惑。
【解决方案2】:

Obj-C 块语法很难阅读,这可以通过使用 typedef 来简化一下。

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

【讨论】:

  • 你的 ReturnedBlock 有 void return,ParamBlock 有 void 参数。
  • 我意识到,您可以根据需要自定义 typedef。主要思想是使用 typedef 使块更具可读性和可理解性,然后语法就不那么重要了。
猜你喜欢
  • 2021-09-28
  • 1970-01-01
  • 1970-01-01
  • 2013-11-21
  • 1970-01-01
  • 2014-03-05
  • 2014-08-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多