的。 val_block = 11 valPointer = 11
调用copy之后的结果呢:
-(void) stackOrHeap{
__block int val =10;
int *valPtr = &val;//使用int的指针,来检测block到底在栈上,还是堆上
blkt1 s= ^{
NSLog(@"val_block = %d",++val);
return val;};
blkt1 h = [s copy];
h();
NSLog(@"valPointer = %d",*valPtr);
}
----------------在ARC下>>>>>>>>>>>无效果。 val_block = 11 valPointer = 10
----------------在非ARC下>>>>>>>>>确实复制到堆上了。 val_block = 11 valPointer = 10
用这个表格来表示 /*当block捕获了自动变量时候 ------------------------------------------------------------------ | where block stay | ARC | 非ARC | -------------------------------------------------------------------
| copy | heap | heap | ------------------------------------------------------------------ | no copy | heap | stack | ------------------------------------------------------------------
*/
__block变量存储区域
当block被复制到堆上时,他所捕获的对象、变量也全部复制到堆上。 回忆一下block捕获自动变量的时候,自动变量将编程一个结构体,结构体中有一个字段叫__forwarding,用于指向自动这个结构体。那么有了这个__forwarding指针,无论是栈上的block还是被拷贝到堆上,那么都会正确的访问自动变量的值。
截获对象
block会持有捕获的对象。编译器为了区分自动变量和对象,有一个类型来区分。
static void __main_block_copy_0(struct __main_block_impl_0 *dst, struct __main_block_impl_0 *src){
_Block_objct_assign(&dst->val,src->val,BLOCK_FIELD_IS_BYREF);
}
static void __main_block_dispose_0(struct __main_block_impl_0 *src){
_block_object_dispose(src->val,BLOCK_FIELD_IS_BYREF);
} BLOCK_FIELD_IS_BYREF代表是变量。BLOCK_FIELD_IS_OBJECT代表是对象 【__block变量和对象】
__block修饰符可用于任何类型的自动变量
【__block循环引用】
根据上面讲的内容,block在持有对象的时候,对象如果持有block,会造成循环引用。解决办法有两种:
1. 使用__weak修饰符。id __weak obj = obj_
2. 使用__block修饰符。__block id tmp = self;然后在block中tmp = nil;这样就打破循环了。这个办法需要记得将tmp=nil。不推荐!
文章开头block测试题答案:ABABB
int val = 10;
void (^blk)(void) = ^{printf("val=%d\n",val);};
val = 2;
blk();
上面这段代码,输出值是:val = 10.而不是2.block截获自动变量的瞬时值。因为block保存了自动变量的值,所以在执行block语法后,即使改写block中使用的自动变量的值也不会影响block执行时自动变量的值。
尝试改写block中捕获的自动变量,将会是编译错误。我更喜欢把这个理解为:block捕获的自动变量都将转化为const类型。不可修改了 解决办法是将自动变量添加修饰符 __block;那么如果截获的自动变量是OC对象呢
^{[array addObject:obj];};
这么写是没有问题的,因为array是一个指针,我们并没有改变指针的值。这个也可以解释下面的问题
const char text[] = "hello";
^{ printf("%c\n",text[2]);};
这样会编译错误。为何?这是因为捕获自动变量的方法并没有实现C语言数组类型。可以通过指针代替:const char *text= "hello";