block本身也是一个oc对象,他内部有一个isa指针。
block可以捕获局部变量,对于全局不需要捕获,所以在block内部可以修改auto,static全局变量的原因。在局部又分为auto/static,对于static,block捕获的是指针,也就是变量的地址,而对于auto变量block捕获的是值,注意是变量的值。这就是为什么不能修改block外部auto变量的原因。如下列子
int a = 1000;
static int b = 200;
void (^block)(NSString *) = ^(NSString * name){
nslog(@"%d-%d",a , b);
}
a = 1000000;
b = 300;
block("g");//最后打印 1000 - 300;
你会发现a的值没有修改成功,为什么这样,其实就是上面所讲,auto修饰的,是将遍历当参数传递给block,但是仅仅是传值,而static修饰的变量,是传递的地址,所以能修改值。
如果转成c++文件,在终端用clang打开源码,就能看见,内部有一个__main_block_impl_0的结构体,而我们auto修饰的变量a,是从impl.FuncPtr == 获取的,所以就算你将a的值从新赋值,最终还是从impl.FuncPtr 取值,所以就不能修改成功。如果想要修改成功,我们只需要在变量前面加上__block就是,这样修饰后,其实就是讲他包装成一个对象处理的。
block分为global,malloc,static三种类型,分别位于内存数据区、堆区、栈区。
怎么区分呢,捕获外部auto就是static,没有就是global,如果进行了copy操作就是malloc类型block。位于栈上的block一般在函数作用域后就被销毁了,只有为进行了copy操作,引用计数加1,不会销毁,这就是为什么mrc时候,调用block会报错,需要手动进行copy操作,在arc不会,是因为系统替我们加了copy操作。
网友评论