根据Block在内存中的位置,Block可分为三种类型NSGlobalBlock,NSStackBlock,NSMallocBlock。
NSGlobalBlock
这种Block存储在程序的数据区域(跟函数存储在一起),一个没有引用外部变量的Block即为NSGlobalBlock。对于NSGlobalBlock,我们不需要使用copy,即使copy,也不会copy到堆上!
NSStackBlock
如果Block中引用了外部变量,则该Block为NSStackBlock。
对于NSStackBlock,如果不做任何操作,随栈自生自灭。一旦block被调用,则会被copy到堆上,变成NSMallocBlock。
请看如下代码:
typedef void (^dBlock)();
dBlock example_getBlock() {
char d = 'aaa';
return ^{
printf("%c\n", d);
};
}
void example() {
example_getBlock()();
}
上面的代码中,example_getBlock返回了一个NSStackBlock,正常情况下返回一个栈上的对象是会出错的,但是在ARC下,返回的时候会将NSStackBlock拷贝到堆上,而且是autorelease类型的。example_getBlock返回堆上的NSMallocBlock,所以上面的代码可以正常运行。
再看如下代码:
- (NSArray*) getBlockArray
{
int num = 123;
return [[NSArray alloc] initWithObjects:
^{ NSLog(@"this is block 0:%i", num); },
^{ NSLog(@"this is block 1:%i", num); },
^{ NSLog(@"this is block 2:%i", num); },
nil];
}
- (void)test
{
NSArray* obj = [self getBlockArray];
void (^blockObject)(void);
blockObject = [obj objectAtIndex:1];
blockObject();
}
这段代码中,getBlockArray返回一个NSStackBlock数组,而ARC并没有对数组中的block做任何处理,getBlockArray函数结束后,NSArray中的三个block都将被释放。所以在test函数中,blockObject指向一块已经被释放的栈内存,运行时程序会报错。
NSMallocBlock
默认的block是存放在栈上的(NSStackBlock),对于一个NSStackBlock copy一下即可copy到堆上,变成NSMallocBlock。
网友评论