block的标志:^
特点:
1、可以保存代码
2、有返回值
3、有形参
4、调用方式和c语言一样
5、可以访问外部变量,但不能修改变量的值;如果使用__block关键字修饰的变量才可以。
1)创建
格式:
返回类型 ^block名称(参数类型表)=^(参数表){
代码;
};
block跟函数很像
a、不带参数
void (^myBlock)()=^{
NSLog(@“…000”);
};
b、带参数
int(^sumBlock)(int,int)=^(int a,int b){
return a+b;
}
c、用typedef定义block变量
typedef int(^)
定义block变量:
typedef int(^myblock)(int,int);
实现(重写):
myblock sblock = ^(int a,int b){
return a+b;
}
myblock subblock = ^(int a,int b){
return a-b;
}
使用:
NSLog(@“a+b = %d”,sblock(1,2));
NSLog(@“a+b = %d”,subblock(5,2));
如:
//定义一个带block参数的函数
-(void)xxxxxxx:(void(^)(NSString *strr))finishBlock{
NSLog(@"xxxxxxxx");
finishBlock(@"........");
NSLog(@"jjjjjjjj");
}
//调用
- (IBAction)Blockaction:(UIButton *)sender {
[self xxxxxxx:^(NSString *strr) {
NSLog(@"%@",strr);
}];
}
结果:
6、Block的循环引用
1)__weak:表示引用为弱引用。对应在定义property时用的"weak"。弱引用不会影响对象的释放,即只要对象没有任何强引用指向,即使有100个弱引用对象指向也没用,该对象依然会被释放。不过好在,对象在被释放的同时,指向它的弱引用会自动被置nil,这个技术叫zeroing weak pointer。这样有效得防止无效指针、野指针的产生。__weak一般用在delegate关系中防止循环引用或者用来修饰指向由Interface Builder编辑与生成的UI控件。
2)__strong:表示引用为强引用。对应在定义property时的"strong"。所有对象只有当没有任何一个强引用指向时,才会被释放。
注意:如果在声明引用时不加修饰符,那么引用将默认是强引用。当需要释放强引用指向的对象时,需要将强引用置nil。
一个特别要注意的问题
苹果的文档中明确地写道:
You should decorate variables correctly. When using qualifiers in an object variable declaration,
the correct format is:
ClassName * qualifier variableName;
按照这个说明,要定义一个weak型的NSString引用,它的写法应该是:
NSString * __weak str = @"hehe"; // 正确! 而不应该是:
__weak NSString *str = @"hehe"; // 错误!
对于非ARC下, 为了防止循环引用, 我们使用__block来修饰在Block
对于ARC下, 为了防止循环引用, 我们使用__weak来修饰在Block。原理就是:ARC中,Block中如果引用了__strong修饰符的自动变量,则相当于Block对该变量的引用计数+1
不过好在,编译器会及时地给我们一个警告,提醒我们可能会发生这类型的问题:
对这种情况,我们一般用如下方法解决:给要进入Block的指针加一个__block修饰符。
这个__block在MRC时代有两个作用:
- 说明变量可改
- 说明指针指向的对象不做这个隐式的retain操作
一个变量如果不加__block,是不能在Block里面修改的,不过这里有一个例外:static的变量和全局变量不需要加__block就可以在Block中修改。
在ARC引入后,没有了retain和release等操作,情况也发生了改变:在任何情况下,__block修饰符的作用只有上面的第一条:说明变量可改。即使加上了__block修饰符,一个被block捕获的强引用也依然是一个强引用。
#include <stdio.h> int main() { int b = 5; int *a = &b; void (^blockFunc)() = ^(){ int *c = a; }; blockFunc(); return 1; }
程序中,同为int型的指针,a是被Block捕获的变量,而c是在Block内定义的变量。a和c存在的位置完全不同,如果Block存在于堆上(在ARC下Block默认在堆上),那么a作为Block结构体的一个成员,也自然会存在于堆上,而c无论如何,永远位于Block内实际执行代码的函数栈内。这也导致了两个变量生命周期的完全不同:c在Block的函数运行完毕,即会被释放,而a呢,只有在Block被从堆上释放的时候才会释放。
同上理,如果我们直接让Block捕获我们的myController引用,那么这个引用会被复制后(引用类型也会被复制)作为Block的成员变量存在于其所在的堆空间中,也就是为Block增加了一个指向myController对象的强引用,这就是造成循环引用的本质原因。
//------------------------------------------------------------------------------------