block块 官方名称:闭包,类似于C语言中的匿名函数,通常作为delegate的代替品使用
block的使用和方法(函数)类似,包括声明,实现,调用三个部分 不同的是block的声明和实现可以写在方法内部,下面是声明block方法的几种方式
void(^test2)(); //如果没有参数 括号可以省略
NSInteger(^test3)();
NSInteger(^test4)(NSString * str);
NSString*(^test5)(NSString * str,BOOL a);
实现方法
test4 = ^(NSString * str){
NSLog(@"test4%@",str);
NSInteger i = 0;
return i;
};
block支持声明和实现同时写,把它们写在一起是这样的
void(^test6)(NSString * text)=^(NSString * text){
NSLog(@"test=%@",text);
};
和普通方法一样,如果不对block块进行调用则block永远不会执行,声明是告诉编译器,我这里来了位block兄弟,如果有人找(调用)你不能说你不认识.可如果声明了不实现就调用,就会造成系统崩溃,所以,在调用一个无法确定有没有被实现的block方法时需要增加一个判断:
//判断方法是否存在 不存在则不调用 防止调用未实现方法引起崩溃
if (test2) {
test2();
}
block的调用和C方法的调用方式相同,
NSInteger i = test5(@"1",YES);
block的作用范围和变量相同,分为局部和全局block,局部block只能在局部里面实现和调用,而全局则可以在任意一个方法体内实现和调用(不可以在方法体外部进行调用和实现,这里和普通方法有所区别).有时候我们需要为多次重复使用的block方法定义一个简单的名称:
typedef void(^test)(NSInteger str);
这样以后再次声明void(^test)(NSInteger str)格式的block快时就可以:
test block1;
这样声明调用的方式不变,不过实现的时候则趋于属性了,他是这样的
block1 = ^(NSInteger str){
NSLog(@"%d",str);
};
block在实际应用中,主要是用于在不同的类中传递数据,其传递特性是:必须有一方类中包含另一方类的对象,具体使用流程如下(类A 向 类B 传值 改变类B的背景颜色):
//1.声明一个 block 类型,返回值表明传值的结果,参数表明传值的数据。
typedef void(^block)(UIColor* color);
//2.声明一个 block 属性。
@property (nonatomic, copy) block block;
//3.调用 block 进行传值。
if (_block) {
//调用 block 前需要判断 block 是否实现。
_block(_colors[sender.selectedSegmentIndex]);
}
//4.实现 block 并获取传过来的值。
vc.block = ^(UIColor* color){
self.view.backgroundColor = color;
};
第1 2 3 是类A中的代码4为类B中的代码.
block中的内存管理比较复杂,对于block自身的内存管理与其他类型的变量或属性相同,声明为属性时需要用copy,但是block不仅要管理自身的内存.它还会对方法快中使用的外部变量进行引用计数加一,如果使用了本类对象的属性.那么就会对self进行retain,这是非常糟糕的事情,会让你的内存管理变得无从下手,什么时候释放?释放谁?怎么解决self被retain后的循环引用问题?有一个很简单的办法:
//使用__block语句修饰将要在block块中使用的对象
__block NSArray* array1 = [[NSArray alloc] initWithObjects:@"array1Object", nil];
//如果是 self,需要这样做,声明新的 __block 修饰的变量等于 self,然后在 block 中使用新的变量代替 self。
__block ViewController* blockSelf = self;
block中是不允许修改外部变量的值得,如果必须要修改则需要在变量前面添加__block 否则将会失败
虽然写了这么多,可看了更多的博客以后发现自己对block的认知越来越模糊了.什么时候使用,怎么正确的使用又成了问题.