Objective-C 的 block 语法看起来比较复杂,其实它只是一个简单的扩展。下面我们从 C 的声明符开始,一步一步地引入 block 概念。

声明符

首先复习一下 C 的声明符:

int a

int指定了类型,a是变量的名称。

声明符可以使用修饰符,C 有三种修饰符:*[]()

指针

int *a

a是指向int的一个指针。

数组

int a[]

a是一个由int组成的数组。

函数

int f()

f是一个返回int的函数。

混合

这些修饰符可以混合使用。混合时,从变量名称开始往右读,读到尽头或闭括号之后再从变量名称开始往左读。

例如:

int *a[]

先往右读,[]是有一个数组,再往左读int *是指向int的指针。所以int *a[]就是由指向int的指针组成的数组,等价于int *(a[])

再如:

int (*a)[]

先由a往右读,碰到),因此再往左读,读到*,因此是一个指针。然后再往右读[],再往左读int。所以最后int (*a)[]是指向由int组成的数组的指针。

同理,int *f(),是一个函数,返回一个指向int的指针。而int (*f)()则是一个指针,指向一个返回int的函数。

block 修饰符

Apple 在上述三个修饰符的基础上增加了一个修饰符,block 修饰符^.

block 修饰符和指向函数的指针非常相似。上面我们提到int (*f)()是一个指向返回int函数的指针,类似地,int (^b)() 是一个指向返回int函数的 block 指针,简称返回int的 block。

因为 block 总是指向函数的,所以int ^aint ^b()都是非法的,因为不存在指向int的 block。

block 和指向函数的指针的区别在于,block 创建了一个闭包。

抽象声明符

将声明符中的变量名称去除后,我们就得到了抽象声明符。在 C 中,抽象声明符用于以下三种情形:

  • 映射。int *a; long *b = (long *) a;
  • sizeof()的参数。malloc(sizeof(long *));
  • 声明函数的参数。int f(long *);

Objective-C 扩展了抽象声明符的用法:用于声明方法的参数和返回值。

- (long **)methodWithArgument:(int *)a;

同样适用于 block 声明符:

- (void)methodWithArgument:(int(^)())block;
- (void)anotherMethodWithArgument:(void(^)(long arg1))block;

block 字面量

^除了作为修饰符使用之外,还可以作为操作符使用,将函数转化为 block。

block = ^(long a, long b) {
  int c = a + b;
  return c;
}

注意我们这里省略了 block 的返回值的类型声明,因为 Objective-C 会从return语句中推导出类型。

总结

Objective-C 的 block 语法是在 C 的标准语法基础上的扩展。Objective-C 中的 block 不过是一个创建了闭包的指向函数的指针。


原文 From C Declarators to Objective-C Blocks Syntax
编译 SegmentFault


weakish
24.6k 声望844 粉丝

a vigorously lazy deadbeat with matured immaturity