block介绍
- Block是iOS4.0之后新增的一种语法结构,也称为“闭包”。
- Block是一个匿名的函数代码块,此代码块可以作为参数传递给其他对象。
- 可以把block当做Objective-C的匿名函数,block是OC中的一种数据类型,
^
是block的特有标记。
block原型
(返回类型)(^block名称)(参数类型)=^(参数列表){代码实现};
|
|
上面的代码声明了一个block(^)原型,名字叫做myBlock,包含一个int型的参数,返回值为NSString类型的指针。
block的定义:
|
|
上面的代码中,将一个函数体赋值给了myBlock变量,其接收一个名为paramA的参数,返回一个NSString对象.
注意:一定不要忘记block后面的分号。
定义好block后,就可以像使用标准函数一样使用它了:
myBlock(6);
由于block数据类型的语法会降低整个代码的阅读性,所以常使用typedef来定义block类型。例如,下面的代码创建了GetPersonEducationInfo和GetPersonFamilyInfo两个新类型,这样我们就可以在下面的方法中使用更加有语义的数据类型。
|
|
我们用一张图来总结一下block的结构:
block数据结构定义
上图这个结构是在栈中的结构,我们来看看对应的结构体定义:
|
|
从上面代码看出,Block_layout
就是对block结构体的定义:
isa
指针:指向表明该block类型的类。flags
:按bit位表示一些block的附加信息,比如判断block类型、判断block引用计数、判断block是否需要执行辅助函数等。reserved
:保留变量,我的理解是表示block内部的变量数。invoke
:函数指针,指向具体的block实现的函数调用地址。descriptor
:block的附加描述信息,比如保留变量数、block的大小、进行copy
或dispose
的辅助函数指针。variables
:因为block有闭包性,所以可以访问block外部的局部变量。这些variables
就是复制到结构体中的外部局部变量或变量的地址。
block使用
作为一个局部变量
1returnType (^blockName)(parameterTypes) = ^returnType(parameters);作为属性
1@property (nonatomic, copy, nullability) returnType (^blockName)(parameterTypes);作为一个方法参数
1- (void)someMethodThatTakesABlock:(returnType (^nullability)(parameterTypes))blockName;作为参数的方法调用
1[someObject someMethodThatTakesABlock:^returnType (parameters)];作为一个typedef
12typedef returnType (^TypeName)(parameterTypes);TypeName blockName = ^returnType(parameters) ;
使用block应当注意的问题
- Block访问外部变量
- block内部可以访问外部的变量,block默认是将其复制到其数据结构中来实现访问的。
- 默认情况下,block内部不能修改外面的局部变量,因为通过block进行闭包的变量是const的。
- 给局部变量加上
__block
关键字,这个局部变量就可以在block内部修改,block是复制其引用地址来实现访问的。
- Block作为属性应该用copy修饰
- 当用weak、assign修饰block属性时,block访问外部变量,此时block的类型是栈block。保存在栈中的block,当block所在函数\方法返回\结束,该block就会被销毁。在其他方法内部调用访问该block,就会引发野指针错误
EXC_BAD_ACCESS
。 - 当用copy、strong修饰block属性时,block访问外部变量,此时block的类型是堆block。保存在堆中的block,当引用计数器为0时被销毁,该类型block是由栈类型的block从栈中复制到堆中形成的,因此可以在其他方法内部调用该block。在ARC下,
strong
和copy
都可以用来修饰block,但是建议修饰block属性使用copy
。
- 当用weak、assign修饰block属性时,block访问外部变量,此时block的类型是栈block。保存在栈中的block,当block所在函数\方法返回\结束,该block就会被销毁。在其他方法内部调用访问该block,就会引发野指针错误