Blocks的总结
Block用来实现类与类之间的通信,使用起来简单方便:
- Block概念
- Block的使用
- Block的声明实现和调用的一般写法
- *Block中的变量
Block概念
block是类似于函数指针的一段代码块,它最大的特点就是回调,一个block就是一个匿名的内联代码集合,它和函数指针一样有返回值类型,有参数类型。
Block的使用
Block的使用和函数指针一样,分三步实现的:第一步声明一个block,第二步实现block,第三步调用block,声明和实现可以放到一起,只有当调用block的时候才会执行block块中的代码,值得注意的是使用block一定要记得在block块的最后要有分号。
Block的声明实现和调用的一般写法
//声明一个block
int (^myBlock)(int, int);
//实现
myBlock = ^(int a, int b){
return a + b;
};
//调用
int sum = myBlock(30, 40);
//声明和实现合到一块
int (^subBlock)(int, int) = ^(int a, int b){
return a - b;
};
//调用
int sub = subBlock(90, 10);
block作为参数使用:
//重定义一个block类
typedef int(^PersonBlock)(int, int);
//返回一个整型,block是整型作为方法的参数,block有两个整型的参数
-(int)myBlock:(PersonBlock)block;
//返回一个void类型,block是void类型作为方法的参数,block没有参数,虽然block没有参数,这里的()不能不写
-(void)voidBlock:(void(^)())block;
值得注意的是当block作为一个类的property属性使用的时候,声明和调用都是在该类的.m文件中实现的,而实现则是在需要该类的block执行某项操作的时候实现的。
Block中的变量:
局部的基本数据类型变量进入到block中,变量会变成常量,若果需要在block中对变量进行修改,需要加上关键字__block,也可以用static修饰,用static修饰就意味着该变量是一个静态变量
__block int num = 10;
Block block = ^{
NSLog(@"num is %d", num);
};
num = 20;
block();
//局部的OC对象进入到block之前要先让blockcopy一次,该对象会被retain一次,加上__block后,引用计数就不会变
//在MRC中,使用block,对任何一个对象操作,这个对象在创建的时候必须加上__block,否则对象不会被release掉
__block NSObject *obj = [[NSObject alloc] init];
Block block2 = ^{
NSLog(@"%ld",obj.retainCount); //对block进行拷贝操作,
block才会被放入堆区进行操作,如果不拷贝,则block中的代码块都是在栈区操作的。
//在栈区的数据出了作用域就会被销毁,把block放大堆区是为了扩大它的作用范围 [block2 copy]; //不用__block,不用copy,那么obj的引用计数就不会变,要想让block2是一个全局变量,就要对block2copy操作
//block是没有引用计数的,也就是block不是一个对象
// NSLog(@"block count %ld", block2.retainCount); NSLog(@"copy后 %ld", obj.retainCount);
block2();
[block2 release]; //对block2进行release操作不是销毁这个block块,而是说当release这个block的时候它在堆区的作用域到这个方法块的末尾就结束了。
NSLog(@"调用后 %ld", obj.retainCount);
[obj release];
在MRC中,当block中的对象作为另一个对象的属性或实例变量时,block的copy操作,会把这个属性或实例变量所在的对象retain一次,这样就会产生循环引用,解决这种循环引用的方法是创建一个中间变量:
//创建一个中间变量
__block Person *ps = self;
self.block = ^{
NSLog(@"%ld", ps->_personObj.retainCount);
};
在ARC中只需要将__block 换成__weak就可以,为了使用对象的实例变量,一般我们还要在block块中将__weak转成__strong