一.Block基础
语法
block是Objective-C上用来实现匿名函数的特性的一种技术。它是一种特殊的Objective-C对象,实际效果就是一段代码块的回调引用。它主要有几个特点:
- block的代码是内联的,效率高于函数调用。
- block对于外部变量默认是只读属性。
- block被Objective-C看成是对象处理
Block变量的声明格式为: 返回值类型(^Block名字)(参数列表)
Block变量的定义格式为: Block变量 = ^(参数列表){函数体}
typedef 返回值类型(^Block名字)(参数列表)
基本用法
Block 可以捕获来自外部作用域的变量,这是Block一个很强大的特性。默认情况下,Block 中捕获的到变量是不能修改的,如果想修改,需要使用__block
进行声明:
- (void)testFuc(){
__block int a = 10;
void (^testBlock)(void) = ^{
a = 42;
NSLog(@"int a:%i",a);//最后打印int a:42
}
testBlock();
}
高级用法
- 在非 ARC 的情况下,对于 block 类型的属性应该使用
copy
,因为 block 需要维持其作用域中捕获的变量。 - 在 ARC 中编译器会自动对 block 进行 copy 操作,因此使用
strong
或者copy
都可以,没有什么区别,但是苹果仍然建议使用copy
来指明编译器的行为。 - block 在捕获外部变量的时候,会保持一个强引用,当在 block 中捕获
self
时,由于对象会对 block 进行copy
,于是便形成了引用循环。
由于block的属性是copy
的,所以也解释了从block外部捕获的变量是不能修改的且是强引用的。避免循环引用的方法一般是声明一个__weak
的临时变量。
typedef (^testBlock)(void)
@interface Test : NSObject
@property (nonatomic, copy) testBlock completeHandle;
@end
@implementation
- (void)configureBlock {
__weak typeof(self) weakSelf = self;//使用weakSelf的话,不能保证weakSelf在block执行的时候不是nil。
self.completeHandle= ^{
__strong typeof(weakSelf) strongSelf = weakSelf;//使用strongSelf能保证在block内部执行的时候不是nil。
[strongSelf doSomething];
[strongSelf doMoreThing];
};
}
为什么有可能 block 执行的过程当中 weakSelf 变为 nil?
weak
置 nil 的操作发生在 dealloc 中,最后一个持有 object 的对象被释放的时候,会触发对象的 dealloc,而这个持有者的释放操作就不一定保证发生在哪个线程了。因此 block 执行的过程中 weakSelf 有可能在另外的线程中被置为 nil。
简而言之,在多线程环境下weak
是无法保证在确定的线程中被置为nil的,可能导致在block执行中对象的上下文不一致。