Block是苹果在iOS4开始引入的对C语言的扩展,用来实现匿名函数的特性,Block是一种特殊的数据类型,其可以正常定义变量、作为参数、作为返回值,特殊地,Block还可以保存一段代码,在需要的时候调用,目前Block已经广泛应用于iOS开发中,常用于GCD、动画、排序及各类回调。
block的优点
- block的代码是内联的,效率高于函数的调用
- block对于外部变量默认是只读的
- block被OC看成对象处理
block的声明与定义
注: Block变量的赋值格式可以是: Block变量 = ^返回值类型(参数列表){函数体};,不过通常情况下都将返回值类型省略,因为编译器可以从存储代码块的变量中确定返回值的类型
typedef 定义block简化版
// 1.使用typedef定义Block类型
typedef int(^MyBlock)(int, int);
// 2.定义一个形参为Block的OC函数
- (void)useBlockForOC:(MyBlock)aBlock{
NSLog(@"result = %d", aBlock(300,200));
}
// 3.声明并赋值定义一个Block变量
MyBlock addBlock = ^(int x, int y){
return x+y;
};
// 4.以Block作为函数参数,把Block像对象一样传递
[self useBlockForOC:addBlock];
// 将第3点和第4点合并一起,以内联定义的Block作为函数参数
[self useBlockForOC:^(int x, int y){
return x+y;
}];
Block 内访问局部变量
- 在Block中可以访问局部变量
- 在声明Block之后、调用Block之前对局部变量进行修改,在调用Block时局部变量值是修改之前的旧值
- 在Block中不可以直接修改局部变量
- 当block对全局变量和静态变量(static修饰的变量)进行操作时将不会出现上述问题
注: 原理解析,通过clang命令将OC转为C++代码来查看一下Block底层实现,clang命令使用方式为终端使用cd定位到main.m文件所在文件夹,然后利用clang -rewrite-objc main.m将OC转为C++,成功后在main.m同目录下会生成一个main.cpp文件
Block在MRC下的内存管理
- 默认情况下,Block的内存存储在栈中,不需要开发人员对其进行内存管理
- 在Block的内存存储在栈中时,如果在Block中引用了外面的对象,不会对所引用的对象进行任何操作
- 如果对Block进行一次copy操作,那么Block的内存会被移动到堆中,这时需要开发人员对其进行release操作来管理内存
- 因为对Block进行一次copy操作,那么Block的内存会被移动到堆中,在Block的内存存储在堆中时,如果在Block中引用了外面的对象,会对所引用的对象进行一次retain操作,即使在Block自身调用了release操作之后,Block也不会对所引用的对象进行一次release操作,这时会造成内存泄漏
- 为了不对所引用的对象进行一次retain操作,可以在对象的前面使用下划线下划线block来修饰
Block的循环引用
- 如果对象内部有一个Block属性,而在Block内部又访问了该对象,那么会造成循环引用
- block不是self的属性或者变量时,在block内使用self也不会循环引用
- block在copy时都会对block内部用到的对象进行强引用(ARC)或者retainCount增1(非ARC)。在ARC与非ARC环境下对block使用不当都会引起循环引用问题,一般表现为,某个类将block作为自己的属性变量,然后该类在block的方法体里面又使用了该类本身,解决方法如下
// 如果是_xxView这类的循环引用
__weak typeof(self) weakSelf = self;
self.blkA = ^{
__strong typeof(weakSelf) strongSelf = weakSelf;//加一下强引用,避免weakSelf被释放掉
NSLog(@"%@", strongSelf->_xxView); //不会导致循环引用.
};
// ARC下使用弱引用
__weak typeof(self) weakSelf=self;
// MRC下使用__block修饰,告诉block不要在内部对self进行retain
__block typeof(self) weakSelf=self;
__block的作用
__block在MRC下有两个作用
- 允许在Block中访问和修改局部变量
- 禁止Block对所引用的对象进行隐式retain操作
__block在ARC下只有一个作用
- 允许在Block中访问和修改局部变量