block的存储域
根据Block在内存中的位置分为三种类型_NSConcreteGlobalBlock,_NSConcreteStackBlock, _NSConcreteMallocBlock。
_NSConcreteGlobalBlock:类似函数,位于text段;
_NSConcreteStackBlock:位于栈内存,作用域结束后后Block将无效;
_NSConcreteMallocBlock:位于堆内存。
1、当 block 写在全局作用域时,即为 global block;
2、当 block 表达式不引用任何外部变量时,即为 global block;
在以上两种情况下生成的block为_NSConcreteGlobalBlock,其余均为_NSConcreteStackBlock,当 block 从栈拷贝到堆后,当栈上变量作用域结束时,仍然可以继续使用 block,因为此时的block位于堆上,block的类型为:_NSConcreteMallocBlock;所以会将 _NSConcreteMallocBlock 写入 isa如:
impl.isa = &_NSConcreteMallocBlock;
栈上的block:
pragma mark - 栈上的block
-(IBAction)test_2id)sender {
NSArray *array = [self getBlockArrayFromStack];
// [self test];
void(^block)(void);
block = array[2];
block();
}
-(void)test {
NSLog(@"hello world!");
}
- (NSArray *)getBlockArrayFromStack {
NSArray *blockArray = [[NSArray alloc]initWithObjects: ^{NSLog(@"block-1");},
^{NSLog(@"block-2");},
^{NSLog(@"block-3");},nil];
return blockArray;
}
上面代码中注释的[self test]看似对程序无影响,但是打开注释就会导致程序崩溃,关闭则无能正确执行;原因在于:一个方法调用的栈帧没有被新的数据覆盖,仍然保留原来block数据的原因所致。这样显然是不安全的,是不能保证block数据可用的。 |