Objective-C Block
Block 是“带有自动变量值的匿名函数”
WHAT
本文还未整理完
用法
局部变量
1
returnType (^blockName)(parameterTypes) = ^returnType(parameters) {...};
属性
1
@property (nonatomic, copy, nullability) returnType (^blockName)(parameterTypes);
方法参数
1
- (void)someMethodThatTakesABlock:(returnType (^nullability)(parameterTypes))blockName;
方法调用参数
1
[someObject someMethodThatTakesABlock:^returnType (parameters) {...}];
关键字
1
2typedef returnType (^TypeName)(parameterTypes);
TypeName blockName = ^returnType(parameters) {...};
类型
- _NSConcreteGlobalBlock (全局)
- Block 内部只是用了全局变量
- Block 内部没有使用任何外部的局部变量
- _NSConcreteStackBlock (栈)
- MRC 下,默认分配在栈上
- _NSConcreteMallocBlock (堆)
- 手动对 block 执行 copy 操作
- ARC 下,大部分情况会将 block 从栈上复制到堆上
修饰符
__block
MRC ARC 下都可以使用,可以修饰对象,也可以修饰基本数据类型。
会将简单类型转化为较大的 struct,会给内存、调用带来额外的开销__strong
MRC 可以避免循环引用,ARC 下不可以__weak
只能在 ARC 下使用,解决循环引用问题__unsafe_unretained
类似 __weak 修饰符,但不会自动置 nil
注意事项
循环引用
非 ARC
使用 __block 来修饰变量,它不会被 Block 所 __retain__ARC 下
iOS 5 前使用 __unsafe_unretained,缺点是指针释放后不会置空
iOS 5 后使用 __weakBlock 执行完毕后置为 nil
不同类型变量读取
局部自动变量
Block 中只读,Block 定义时 copy 变量的值,在 Block 中作为常量使用,所以即使变量的值在 Block 外改变,也不影响它在 Block 中的值。static 变量、全局变量
Block 可以进行读写操作。因为全局变量或静态变量在内存中的地址是固定的,Block 在读取该变量值的时候是直接从其所在内存读出,获取到的是最新值,而不是在定义时copy的常量。Block 变量
等效于全局变量或静态变量
Block 的 copy、retain、release 操作
- Block_copy与copy等效,Block_release与release等效
- retain、copy、release都不会改变引用计数,retainCount 始终是1
- NSConcreteGlobalBlock:retain、copy、release 操作都无效
- NSConcreteStackBlock:retain、release 操作无效
- NSConcreteMallocBlock支持 retain、release,虽然 retainCount 始终是1,但内存管理器中仍然会增加、减少计数。copy 之后不会生成新的对象,只是增加了一次引用,类似 retain
ARC 下 Block 的自动拷贝和手动拷贝
ARC下,以下几种情况,系统会将block从栈上自动复制到堆上
- 当 block 作为函数返回值返回时;
- 当 block 被赋值给 __strong 修饰的 id 类型的对象或 block 对象时;
- 当 block 作为参数被传入方法名带有 usingBlock 的 Cocoa Framework 方法或 GCD 的 API 时(比如使用NSArray 的 enumerateObjectsUsingBlock 和 GCD 的 dispatch_async 方法时,其 block 不需要我们手动执行copy操作)
注:系统方法内部对 block 进行了 copy 操作
因为在 ARC 下,对象默认是用 __strong 修饰的,所以大部分情况下编译器都会将 block 从栈自动复制到堆上,除了以下情况
- block 作为方法或函数的参数传递时,编译器不会自动调用 copy 方法
- block 作为临时变量,没有赋值给其它 block
LINK
How Do I Declare A Block in Objective-C?
Objective-C Blocks Quiz
正确使用Block避免Cycle Retain和Crash