Block(二) 的内存管理以及特性
一 . Block放在哪里
Block 分为三种类型:
- _NSConcreteGlobalBlock (全局block)
- _NSConcreteStackBlock (栈block)
- _NSConcreteMallocBlock (堆block)
这张图里面很好的解释了三个block在内存里面的分布
alt text_NSConcreteGlobalBlock
1. 当block 定义在全局作用域的时候,就是global_block
2. 当block 的方法不获取任何外部变量的时候,就是global_block
除此之外,其他形式的block都是stack_block,当然也有例外。
在这里还是用代码的形式来学习比较合适。
栈和堆
void foo()
{
__block int i = 1024;
int j = 1;
void (^blk)(void);
void (^blkInHeap)(void);
blk = ^{
printf("%d, %d\n", i, j);
};
blkInHeap = CFBridgingRelease((__bridge CFTypeRef _Nullable)(blk));
}
- (void)fooBar
{
void (^blk)(BOOL);
BlockTest* t = [[BlockTest alloc]init];
t.block = blk;
void (^oblk)(void) = ^{ printf("%d\n", t.block);};
void (^oblkInHeap)(void) = [oblk copy];//oblkInHeap在堆中
}
对于堆跟栈block的变量,我们可以看下面这个例子。
- (void)tt{
__block int i = 1024;
int j = 1;
void (^block)(void);
block = ^{
NSLog(@"%d,%d",i,j);
};
block();
void(^blockInHeap)(void) = [block copy];
blockInHeap();
i++;
j++;
block();
blockInHeap();
}
我在这里解释一下这段代码过程中发生的事情。
在我们定义一个__block int i;之后i就已经在栈上了,之后我们定义j,j还不在栈上。
在我们block = ^{} 的时候他会拷贝没有__block标记变量的内存区,这时候j就在栈上了。
void(^blockInHeap)(void) = [block copy];的时候会拷贝block的内存去到堆上。
在i++ j++之后,由于之前就已经拷贝了一份j的复制品,这时候展示出来的j是在栈上的j,而不是真正的j。而i不同,因为i被记录下来的是地址。
全局block
static int(^maxIntBlock)(int, int) = ^(int a, int b){return a>b?a:b;};
对于全局block里面的变量与block的存储没什么关系,反正是全局变量,大家都访问得到。
二 . 其他特性
对block进行复制:
- 对全局的block 调用copy,会返回原指针。(这个很好理解)
- 对于栈上block 调用copy,会返回新复制到堆上的block的指针,而且__block变量也会被多拷贝一份。
- 对于在heap上的block,调用copy,只会增加他的饮用计数
网友评论