Block的类
类 | 设置对象的储存域 |
---|---|
_NSConcreteStackBlock |
栈区 |
_NSConcreteGlobalBlock |
程序的数据区(全局区) |
_NSConcreteMallocBlock |
堆区 |
Block分配的规律
Block不论在ARC下还是在MRC下,都会视情况被分配到这三种区中。我总结了分配在各种区的条件,如下:
-
NSConcreteGlobalBlock
:无论此block是否被持有,block内没有引用外部变量 -
NSConcreteStackBlock
: 此block必须未被持有,并且引用了外部变量 -
NSConcreteMallocBlock
:此block必须被持有,并且引用了外部变量
Block执行过copy后的情况
Block的类 | 副本源的配置储存域 | 复制效果 |
---|---|---|
_NSConcreteStackBlock |
栈区 | 从栈复制到堆 |
_NSConcreteGlobalBlock |
全局区 | 什么也不做 |
_NSConcreteMallocBlock |
堆区 | 引用计数增加 |
栈上的Block什么时候会被复制到堆
- 调用Block的
copy
实例方法 - Block作为函数返回值返回时
- 将Block赋值给附有
__strong
修饰符id
类型的类或Block类型成员变量时 - 在方法名中含有
usingBlock
的Cocoa
框架方法或Grand Central Dispatch
的API中传递Block时
接下来就结合代码来分析Block的内存分配。
等号左侧在OC默认情况下属于强指针,用__weak修饰后变成弱指针,右侧Block不会被持有,并且Block引用了外部变量,所以会被分配在栈区
int temp = 10;
__weak void(^blk_t1)(void) = ^{
NSLog(@"%d",temp);
};
NSLog(@"1===%@",blk_t1);
等号左侧在OC默认情况下属于强指针,右侧block被持有,引用外部变量就分配在堆区
int temp = 10;
void(^blk_t)(void) = ^{
NSLog(@"%d",temp);
};
blk_t();
NSLog(@"2===%@",blk_t);
等号左侧在OC默认情况下属于强指针,右侧block被持有,不引用外部变量就分配在全局区
void(^blk_tt)(void) = ^{
};
NSLog(@"3===%@",blk_tt);
此block未被持有,且引用了外部变量,所以分配在栈区
int temp = 10;
NSLog(@"4===%@",^{
NSLog(@"%d",temp);
});
栈区的block在执行copy后会被分配到堆区
int temp = 10;
NSLog(@"5===%@",[^{
NSLog(@"%d",temp);
} copy]);
等号左侧在OC默认情况下属于强指针,右侧block被持有,block内部未引用外部变量,被分配到全局区,执行copy后依然在全局区
void (^blk_ttt)(void) = ^() {
};
blk_ttt();
NSLog(@"\n6===\n拷贝前%@\n拷贝后%@",blk_ttt,[blk_ttt copy]);
block使用内部局部变量,未引用外部变量,依然是全局block
void (^blk_tttt)(void) = ^{
int b = 20;
NSLog(@"%d",b);
};
blk_tttt();
NSLog(@"7===%@",blk_tttt);
block内部使用传进来的参数,并不会持有该参数,此block在使用了参数后依然是全局block
NSString *str = @"I love China!";
void (^blk_ttttt)(NSString *) = ^(NSString *param){
NSLog(@"%@",param);
};
blk_ttttt(str);
NSLog(@"8===%@",blk_ttttt);