第一、在OC中允许block改写值的变量有三种:
- 静态变量
- 全局变量
- 静态全局变量
code示例如下所示:
int global_val=1;
staticint static_global_val=2;
int main(int argc,const
char * argv[]) {
@autoreleasepool {
static int static_val=3;
void (^blk)(void)=^{
global_val *=2;
static_global_val+=3;
static_val+=4;
NSLog(@"global_val is %d",global_val);
NSLog(@"static_global_val is %d",static_global_val);
NSLog(@"static_val is %d",static_val);
};
blk();
return 0;
}
}
执行结果:
global_val is 2
static_global_val is 5
static_val is 7
第二、Block存储域
__block说明符严格意义上来说是一种存储域说明符,用来指定该变量的存储位置
在C语言中,static表示存在静态变量区域,auto表示存储在栈中,register表示存在寄存器,__block变量是结构体类型的自动变量
Block是objective-c对象,_NSConcreteStackBlock表示存储为栈,_NSConcreteGlobalBlock表示全局变量区,
_NSConcreteMallocBlock表示存储区域是堆
1、_NSConcreteGlobalBlock实例
当block变量不适用截获的自动变量时,可以采用全局变量,如下所示
typedef void(^TEST)(void);
TEST test;
int main(int argc, const char * argv[]) {
@autoreleasepool {
int val=3;
test=^{
}
test();
return 0;
}
}
2、_NSConcreteStackBlock栈类型block变量最常见
配置在全局变量的block,在变量作用域外通过指针可以安全地访问,但设置在栈上的block,如果其所属的变量作用域结束了,该block就被废弃,
复制到堆上的__block变量在变量作用域结束时不受影响
__block变量用结构体成员变量__forwarding可以实现无论__block变量配置在栈上还是配置在堆上都能够正确访问__block变量第四、
__block变量用结构体成员变量__forwarding实现无论__block变量无论在配置在栈还是配置在堆上,都能够正确访问__block变量
对于_NSConcreteStackBlock变量执行copy,会从栈复制到堆
对于_NSConcreteGlobalBlock变量执行copy,什么也不做
对于_NSConcreteMallocBlock变量执行copy,引用计数增加
copy示例:
blk=[[[[blk copy]copy]copy]copy];
解释为如下
{ /*
*blk复制到堆
*将配置在堆上的block赋值给变量tmp
*变量tmp持有强引用的block
*/
blk_t tmp=[blk copy];
/**
* blk和tmp强引用block
*/
blk=tmp;
}
跳出作用域,tmp执行release释放,blk只有block没有被释放,以此循环。
结论:不管block配置在何处,用copy方法复制都不会引起任何问题,在不确定时用copy方法即可