Block的定义与声明

定义

1
^returnType (args) { functionBody; };

如果returnType为void则可以省略:

1
^(args) { functionBody; };

如果无参数列表args,可以写成void,可以省略,也可以连括号一起省略:

1
2
3
^returnType (void) { functionmBody; }
^returnType () { functionmBody; }
^returnType { functionmBody; }

如果返回类型为void且没有参数,则可以省略成:

1
2
^ { functionmBody; }
^void (void) { functionmBody; }

声明

1
returnType (^blockName) ( argTypes );

如果argTypes为空(即没有参数),只能用(void)代替,不能进一步省略。

如果作为函数参数,则声明略有不同,如下:

1
(returnType (^) ( argTypes )) blockName

举例:

1
- (void) callback: (int (^)(void))blk;

Block的用法

Typedef别名

即使用typedef 声明即可,声明中的blockName即为这个block的别名,举例:

1
2
typedef int (^blk) (void);
blk b = ^int (){ return 1; }; // 此处b才是这个block的真实名字

赋值操作

赋值操作即为声明=定义;

调用

类似函数的调用即可,举例:

1
2
3
typedef int (^blk) (void);
blk b = ^int (){ return 1; };
b();

变量的两种引用形式

不需要改变值

不需要改变值的变量直接使用即可,进行的是值传递,即在定义block之前的值会被传进去。

需要改变值

需要用__block修饰该变量,如果涉及到self,则需要将self转换成weakSelf避免循环引用,即:

1
__weak __typeof(self)weakSelf = self;

之后对self的操作都使用weakSelf来操作,如果持有该block的对象被释放,则该weakSelf也会置nil。

p.s. 只有会产生循环引用的情况才需要转换成weakSelf。

而在一个block中,weakSelf随时都可能因为引用它的对象的销毁而置空,因此可以使用再次转为strongSelf的方式,即:

1
__strong __typeof(self) strongSelf = weakSelf;

这样就可以防止在block的运行过程中的weakSelf的意外置nil。

Block的用途

枚举

1
2
- (void)enumerateObjectsUsingBlock:(void (NS_NOESCAPE ^)(ObjectType obj, NSUInteger idx, BOOL *stop))block;
- (void)enumerateObjectsWithOptions:(NSEnumerationOptions)opts usingBlock:(void (NS_NOESCAPE ^)(ObjectType obj, NSUInteger idx, BOOL *stop))block;

具体对NSArray中的每一个对象的操作均在block中进行。注意这里的(NSEnumerationOptions)opts 有两个选项:

  • NSEnumerationReverse,逆序访问

  • NSEnumerationConcurrent,同步访问,不保证顺序,但速度较快

UIView动画

参见iOS动画总结-Block动画 中的第一部分,UIView的两种Block动画实现方式。

排序

1
2
3
- (void)sortUsingComparator:(NSComparator NS_NOESCAPE)cmptr;
[arrs sortUsingComparator:^NSComparisonResult(id _Nonnull obj1, id _Nonnull obj2) {
}];

这个比较函数的Block,返回类型NSComparisonResult有三个枚举:

  • NSOrderedAscending - obj1 < obj2

  • NSOrderedSame - obj1 = obj2

  • NSOrderedDescending - obj1 > obj2

Completion handler与错误处理

主要是在某些方法中含有Block类型的参数,可以用作completion handler和错误处理。

GCD多线程控制

参见iOS多线程-GCD 中的GCD相关部分