设为首页 加入收藏

TOP

OC高级编程――深入block,如何捕获变量,如何存储在堆上(三)
2015-01-22 20:57:45 来源: 作者: 【 】 浏览:46
Tags:高级 编程 深入 block 如何 捕获 变量 存储
的。 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";
首页 上一页 1 2 3 下一页 尾页 3/3/3
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇简述C疑难杂症_序列点(二) 下一篇C语言其实不简单:sizeof

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容: