7.7 Bolck
定义
- 带有自动变量的匿名函数。本质是一个OC对象
- 匿名函数:没有函数名的函数,一对{}包裹的内容是匿名函数的作用域。
- 自动变量:栈上声明的一个变量不是静态变量和全局变量,是不可以在这个栈内声明的匿名函数中使用的,但在Block中却可以。
- 虽然使用Block不用声明类,但是Block提供了类似Objective-C的类一样可以通过成员变量来保存作用域外变量值的方法,那些在Block的一对{}里使用到但却是在{}作用域以外声明的变量,就是Block截获的自动变量
内部结构
表达式
- ^ 返回值类型 (参数列表) {表达式}
^ int (int count) { return count + 1; };
Block类型变量
- 返回值类型 (^变量名)(参数列表) = Block表达式
int (^blk)(int) = ^(int count) { return count + 1; };
typedef声明Block
- typedef 返回值类型 (^变量名)(参数列表)
typedef void(^ResultBlock)(NSString *name, NSString *imgFilePath); //声明一个block变量 @property (nonatomic, copy) ResultBlock result;
当Block类型变量作为函数的参数
- (void)setTimerWithId:(NSString *)tid result:(void (^)(NSInteger code, NSDictionary *data))result;
}
- (void)func:(ResultBlock)blk {
NSLog(@"Param:%@", blk);
}
Block类型变量作返回值
- (void (^)(NSInteger code, NSDictionary *data))setTimerWithId:(NSString *)tid ;
}
- (ResultBlock)func:(NSString *)str {
NSLog(@"Param:%@", str);
}
typedef int (^blk_k)(int);
- (blk_k)funcR {
return ^(int count) {
return count ++;
};
}
Block的变量捕获(capture)
为了保证Block内部能够真正访问外部的变量,Block有个变量捕获机制
捕获:Block内部会新增一个成员变量来存储外部的值
-
捕获的条件:判断是局部变量,还是全局变量,局部变量会捕获,全局变量不会捕获
- auto:作用域一过,就到销毁了,访问不到内存,所以block内部只能是指传递,在block外面不能修改。
- static:类变量,类存在就不会被销毁,所以可以指针传递,在block外面不能修改。
- 全局变量:不会捕获到block内部,可以直接访问
Block的类型
- 堆:动态分配内存,需要自己手动申请,需要自己管理内存
- 栈:系统自动分配内存,系统自己会销毁
- Global:没有访问auto变量
- Stack:(MRC)访问了auto变量
- malloc:Stack调用了copy
-
每一种block调用了copy后的结果:
Block的copy
Block的对象类型的auto变量
- 对象类型的auto变量,MRC下放到了栈空间,ARC下放到了堆空间
- 栈空间的block不会拥有外面的对象的,对象在block释放之前,对象会被释放
- 堆空间的block有能力去保住对象,对象在block释放之前,对象不会被释放
- ARC:强引用默认做了copy操作,block放到了堆空间,如果对象用__weak修饰,对象会被释放,用__strong修饰,对象不会被释放
- MRC:没有copy,block放到了栈空间
Block内部修改变量
- 把局部变量改成全局变量
- 用static修饰,把局部变量改成静态变量
- 加__block修饰
-
只能修饰局部变量,不能修饰全局变量和静态变量
-
__block的内存管理
对象类型的auto变量,__block变量
-
forwarding的指向
block的循环引用
- __weak:把一个设置成弱引用
- __unsafe_unretain:和__weak,但是不不把引用对象设置为nil
- __block:要调用block,并将对象设置为空。