Block是一种比较特殊的数据类型。它可以保存一段代码,在合适的时候取出来调用。
◦ 我们可以把Block当做Objective-C的匿名函数。Block允许开发者在两个对象之间将任意的语句当做数据进行传递,往往这要比引用定义在别处的函数直观。另外,block的实现具有封闭性(closure),而又能够很容易获取上下文的相关状态信息。
◦ block是代码块,其本质和变量类似。不同的是代码块存储的数据是一个函数体。使用Block,就可以像其他标准函数一样,传入参数,并得到返回值。
block的格式:
a:Block的返回值类型,可以为空(void);
b:Block对象名称,可以理解为变量名;
^:块的语法标记,声明b为一个Block对象;
c:第一个参数类型
d:第二个参数类型
name1,name2:参数名;
{}:Block代码块的主题部分。
Block使用场景,可以在两个界面的传值,也可以对代码封装作为参数的传递等。用过GCD就知道Block的精妙之处。
Block的修饰
ARC情况下
1.如果用copy修饰Block,该Block就会存储在堆空间。则会对Block的内部对象进行强引用,导致循环引用。内存无法释放。
解决方法:
新建一个指针(__weaktypeof(Target) weakTarget = Target )指向Block代码块里的对象,然后用weakTarget进行操作。就可以解决循环引用问题。
2.如果用weak修饰Block,该Block就会存放在栈空间。不会出现循环引用问题。
MRC情况下
用copy修饰后,如果要在Block内部使用对象,则需要进行(__block typeof(Target) blockTarget =Target )处理。在Block里面用blockTarget进行操作。
Block结合typedef使用
自己定义一个Block类型,用定义的类型去创建Block,更加简单便捷。
这里举例一个Block回调修改上一下界面的背景颜色。ViewController1 控制器1,ViewController2 控制器2,控制器1跳转到控制器2,然后在控制器2触发事件回调修改控制器1的背景颜色为红色。
ViewController2的实现
#import <UIKit/UIKit.h>
@interfaceViewController2 : UIViewController
/**
* 定义了一个changeColor的Block。这个changeColor必须带一个参数,这个参数的类型必须为id类型的
* 无返回值
* @param id
*/
typedefvoid(^changeColor)(id);
/**
* 用上面定义的changeColor声明一个Block,声明的这个Block必须遵守声明的要求。
*/
@property (nonatomic, copy) changeColorbackgroundColor;
@end
-(void)touchesBegan:(NSSet<UITouch *> *)toucheswithEvent:(UIEvent *)event{
//声明一个颜色
UIColor *color = [UIColor redColor];
//用刚刚声明的那个Block去回调修改上一界面的背景色
self.backgroundColor(color);
}
ViewController1的实现
-(void)touchesBegan:(NSSet<UITouch *> *)toucheswithEvent:(UIEvent *)event{
ViewController2*vc =[[ViewController2 alloc]init];
// 回调修改颜色
vc.backgroundColor = ^(UIColor *color){
self.view.backgroundColor = color;
};
[self.navigationController pushViewController:vcanimated:YES];
}
__block关键字的使用
◦ 在Block的代码块里,是不能修改在外面定义的变量,并且在给block赋值的时候,已经对代码块里的变量做了值的拷贝(只读不可修改)。
int x = 5;
int (^block4)(int) =^(int y) {
int z =x + y;
returnz;
};
NSLog(@"%d,%d",x+=5,block4(5)); 打印的值是10,10;
分析:变量x在Block外定义的,在Block代码块编译的时候,取的x的值为之前的5(不可修改)。因此即使执行x += 5的使x的值变为10,但Block代码块里的x依然是5,所以block(5)的值为5+5=10。
◦ 在变量前添加__block关键字进行修饰后,此变量在Block代码块里的就是可更改的(可读可写),执行代码时取变量最新的值。
__block int x = 5;
int (^block4)(int) =^(int y) {
int z =x + y;
returnz;
};
NSLog(@"%d,%d",x+=5,block4(5)); 打印的值是10,15;
当一个对象中的block块中的访问自己的属性会不会造成循环引用?
Block内部使用外部的一个对象,如果外部对象是强引用那么内部会自动生成一个强引用,引用着外部对象。如果外部对象是弱引用那么内部会自动生成一个弱引用,引用着外部对象。
在ARC下,只加一个__weak关键词就可以
在非ARC下,只加一个__block关键词就可以
去禁止block对self进行强引用或者强制增加引用计数。
若产生警告,weak变量被release掉,block代码块未执行,则
1)ARC环境下:ARC环境下可以通过使用_weak声明一个代替self的新变量代替原先的self,我们可以命名为weakSelf。通过这种方式告诉block,不要在block内部对self进行强制strong引用:(如果要兼容ios4.3,则用__unsafe_unretained代替__weak,不过目前基本不需考虑这么low的版本)
1 self.arr= @[@111, @222, @333];
2 __weak typeof(self) weakSelf=self;
3 self.block= ^(NSString *name){
4 NSLog(@"arr:%@", weakSelf.arr); };
2)MRC环境下:解决方式与上述基本一致,只不过将__weak关键字换成__block即可,这样的意思是告诉block:小子,不要在内部对self进行retain了!
http://www.jianshu.com/p/17872da184fb
http://www.cnblogs.com/laoNanHai/p/5537037.html
http://www.cnblogs.com/wengzilin/p/4347974.html
http://blog.csdn.net/fengsh998/article/details/38090205