系列文章:
iOS Block实现原理
iOS Block __block说明符
iOS Block存储域及循环引用
最近又翻了一遍《Objective-C高级编程》,每读一遍感觉都不一样,理解的东西印象更深了。在此做一下笔记。推荐iOS开发者细读几遍,很受益。
通过下面几点来简单介绍下Block:
- Block概要
- Block语法
- Block类型变量
- Block截获自动变量值
- __block说明符
- 截获OC对象
Block概要
什么是Block:带有自动变量(局部变量)的匿名函数
匿名函数:没有名称的函数。
自动变量:局部变量、函数参数。
其他语言中的Block的名称
程序语言 | Block的名称 |
---|---|
C+ Block | Block |
Smalltalk | Block |
Ruby | Block |
Python | Lambda |
C++ | Lambda |
JS | Anonymous function |
Block语法
^ 返回值类型 参数列表 表达式
例:
^ NSString * (NSString *str) {
return [str stringByAppendingString:@"======"];
};
返回值类型 参数列表可以省略;
^ 表达式
例:
^{
NSLog(@"我是block");
};
Block类型变量
block和C语言函数相比,除了没有^和函数名称,其他都相同。
声明Block类型变量并赋值:
NSString *(^block)(NSString *) = ^ NSString * (NSString *str) {
return [str stringByAppendingString:@"======"];
};
block(@"haha");//block调用
Block 变量赋值:
NSString *(^block1)(NSString *) = block;
也可以使用typedef来给Block变量起别名:
typedef NSString * (^MyBlock)(NSString *);
使用MyBlock类型的属性:
@property (nonatomic, copy) MyBlock block;
函数传递block类型参数:
- (void)function:(NSString *(^)(NSString *name))block {
NSString *str = NSStringFromSelector(_cmd);
NSLog(@"%@",block(str));
}
block 作为函数返回值
- (NSString *(^)(NSString *))function:(NSString *)firstName {
return ^NSString *(NSString *lastName) {
return [firstName stringByAppendingString:lastName];
};
}
NSString *(^block2)(NSString *) = [self function:@"xiao"];
NSLog(@"%@",block2(@"_ming"));
打印:xiao_ming
Block截获自动变量值
通过Block语法和Block类型变量,我们理解了带有自动变量值的 匿名函数 中的 匿名函数,而带有自动变量值究竟是什么呢? 带有自动变量值在Block中表现为 截获自动变量值,实现如下:
- (void)viewDidLoad {
[super viewDidLoad];
int dmy = 256;
int val = 10;
const char *fmt = "val = %d\n";
void (^blk)(void) = ^{
printf(fmt,val);
};
val = 2;
fmt = "These value were changed. val = %d\n";
blk();
}
打印:val = 10 而不是These value were changed. val = 2
在上述代码中,Block语法的表达式使用的是它之前声明的自动变量fmt和val。Block中,Block表达式截获所使用的自动变量的值,即保存该自动变量的瞬间值。因为Block表达式保存了自动变量的值,所以在执行Block语法后,即使改写Block中使用的自动变量的值也不会影响Block执行时自动变量的值。
__block说明符
在不加__block修饰符时,Block截获的是自动变量值的瞬间值,保存后就不能改写该值。
int val = 1;
void (^blk)(void) = ^{
val = 2;
};
报错:Variable is not assignable (missing __block type specifier)变量不能被赋值,缺少__block
要想在Block内部改变变量的值,需要在变量前加上 __block
该变量称为__block变量。后边会说明,__block 到底做了哪些事情。
__block int val = 1;
void (^blk)(void) = ^{
val = 2;
};
截获OC对象
NSMutableArray *array = [NSMutableArray array];
void (^blk)(void) = ^{
[array addObject:@"haha"];
//array = [NSMutableArray array];编译报错,缺少__block修饰符
};
赋值给截获的array对象会编译报错,但是使用截获的值却不会有任何问题。