11

假设我们有这个块:

int (^aBlock)(BOOL) = ^(BOOL param) { ...

我目前对此的理解是:第一个int是返回类型,(^aBlock)(BOOL)给出了方法的名称和它的参数的类型,= ^(BOOL param)是块内部的参数名称......再加上参数的类型?

为什么我们必须两次列出参数类型的语法?这两种类型会有所不同吗?

4

4 回答 4

13

这并不是“两次列出参数类型”,在第一种情况下,您是在声明块变量的类型,在第二种情况下,您正在定义一个块文字。然后,您将文字分配给变量的值。你甚至可以做这样的事情,它是等价的,并且更好地说明了这些实际上是两个完全独立的声明,尽管它们与一个 assign 语句相关联:

id thisBlock = ^id (id x, NSUInteger idx) {
    NSLog(@"x = %@",x);
    return x;
};

id (^thatBlock)(id obj, NSUInteger index) = thisBlock;

它们彼此独立的事实意味着尝试从表达式的左侧到右侧提供某种类型的输入信息的转移或继承可能甚至是不正确的。是的,类型可以不同 - 考虑一下这段代码编译和执行得很好:

id (^thatBlock)(NSArray *, NSDictionary *, NSString *) = ^id (id x, id y, id z) {
    NSLog(@"x = %@",x);
    return x;
};

thatBlock(@[],@{},@"");

希望这可以帮助!

于 2012-10-15T04:13:22.570 回答
4

为什么我们必须两次列出参数类型的语法?

块是这样设计的,所以你可以这样做:

int (^aBlock)(BOOL);

aBlock = ^(BOOL param) {
  ...
};

它只是喜欢

- (int)aMethodWithParam:(BOOL)param;

- (int)aMethodWithParam:(BOOL)param {
  ...
}

这两种类型会有所不同吗?

不,更重要的是,类型的顺序应该是相同的,即:

int (^aBlock)(BOOL, NSString*) = ^(BOOL param, NSString *aString) {
  ...
};

这是块的清晰数字:

图片

于 2012-10-15T04:10:57.593 回答
2

您给出的代码片段不是块声明:它是块声明块定义。首先,您声明一个名为 的标识符aBlock

int (^aBlock)(BOOL)

然后你定义一个块:

^(BOOL param) { ...

这两个都是分别解析和评估的。由于您将一个分配给另一个,编译器会进行类型检查以确保左侧的表达式(您的aBlock声明)与右侧的表达式(块定义)的类型相同。

所以,答案是,这些部分需要单独评估。由于块定义是自行编译的,因此您必须包含 的类型param,否则编译器将不知道它应该是什么类型。(是的,您可以在这种情况下创建一个例外,并查看整个赋值,但是在 C 语言的其他任何地方,您都通过首先给出类型来声明标识符,那么为什么在这里做不同的事情呢?)

但是——你可能会说——如果这是真的,为什么我不必int在右侧定义返回类型 ( ) 呢?

你很精明。答案是,在编写块表达式时,您不需要定义返回类型,因为编译器可以从块内的 return 语句(或缺少)推断它。

(那么为什么你必须在函数定义中包含返回类型?嗯,我猜是历史。编程语言定义是由不完美的人创建的。)

于 2012-10-15T04:11:50.960 回答
0

根据Ry 的 Objective C 教程

块使用与正常功能相同的所有机制。您可以像声明函数一样声明块变量。

 NSInteger (^BlocksAddition)(NSInteger x,NSInteger y)=^NSInteger(NSInteger x, NSInteger y){

    return x+y;
};

NSUInteger result=BlocksAddition(4,5);
NSLog(@"Addition Result:%d",result);
于 2014-07-08T07:26:16.690 回答