一、概述
Block是C级别的语法和运行时特性。Block比较类似C函数,但是Block比之C函数,其灵活性体现在栈内存、堆内存的引用,我们甚至可以将一个Block作为参数传给其他的函数或者Block。
二、热身
先看一个比较简单的Block例子:
int multiplier = 7;
int (^myBlock)(int) = ^(int num) {
return num * multiplier;
};
在这个例子中,myBlock是一个Block变量,它接受一个int类型的参数,返回一个int类型的值。是不是很像C函数?
来,让我们typedef一下
typedef void (^BoolBlock)(BOOL);//一个只接受一个BOOL参数,没有返回值的block
typedef int (^IntBlock)(void);//一个没有参数,返回int的block
typedef BoolBlock (^HugeBlock)(IntBlock);//看看,这个HugeBlock的参数和返回值都是block
三、更详细的例子
注意:上面的typedef都还有效~
主动调用一下:
- (void)someMethod
{
BoolBlock ablock = ^(BOOL bValue) {
NSLog(@"Bool block!");
};
ablock();
}
作为参数返回:
typedef void (^BoolBlock)(BOOL);
- (BoolBlock)foo()
{
BoolBlock ablock = ^(BOOL bValue) {
NSLog(@"Bool block!");
};
return [[ablock copy] autorelease];//一定要copy,将其复制到堆上,更详细的原理,将在后续章节讲解
}
类的一个成员:
@interface OBJ1 : NSObject
@property (nonatomic, copy)BoolBlock block;//理由同上啊,同学们
@end
OBJ1 *obj1 = ...
obj1.block = ^(BOOL bValue) {
NSLog(@"Bool block!");
};
其他函数的参数:
- (void)foo(BoolBlock block)
{
if (block) {
block();
}
}
甚至其他block的参数:
BoolBlock bBlock = ^(BOOL bV){if(Bv){/*do some thing*/}};
HugeBlock hBlock = ^(BoolBlock bB) {bB();};
hBolck(bBlock);
啊,全局变量!:
static int(^maxIntBlock)(int, int) = ^(int a, int b){return a>b?a:b;};
int main()
{
printf("%d\n", maxIntBlock(2,10));
return 0;
}
好了,你知道block大概能怎么用了。
四,特殊的标记,__block
如果要在block内修改block外声明的栈变量,那么一定要对该变量加__block标记:
int main()
{
__block int i = 1024;
BoolBlock bBlock = ^(BOOL bV) {
if (bV) {
i++;//如果没有__block标记,是无法通过编译的。
}
};
}
注意事项:
block可以完全作为delegatge的替代品,而且使用简单,不需要写太多@protocol来定义接口。但使用有以下几点注意。
(1) block不是Object对象,所以对retain无效,要想保留block生命周期,最好通过copy来实现,当然copy后,要记得release。如果不想手动管理,就通过[[[testBlock]
copy] autorelease]来管理。
(2)我们知道一般被block的应用的对象,retainCount会自动加一,为了打破这种 retain circle,可以在对象前加__block,这样block块就不会维护这个对象了。有两种情况
(1)对临时变量的引用如:A a =[ [[A alloc] init] withBlock:^{
[a action];
[ a release];
}];其实这样会导致内存泄漏,要打破这种circle,只需要在A前面加__block。在我的测试代码中,由于没有对A加__block
导致程序直接崩溃。
即
__block A a =[ [[A alloc] init] withBlock:^{
[a action];
[ a release];
}]; 这样A的dealloc方法就会调用
(2)对实例变量的引用如
A a =[ [[A alloc] init] withBlock:^{
[self action];
}];这样即使调用的self 自身类的release 方法,只要这个block没有执行完,self也不会释放。要打破这种可采用如下做法
__block typeof (self) bself = self; 即通过表达式引用,具体参考typeof用法
,指明 bself 是self类型。
A a =[ [[A alloc] init] withBlock:^{
[bself action];
}];这样块和self相互独立了。