码迷,mamicode.com
首页 > 其他好文 > 详细

block存储区域——如何验证block在栈上,还是堆上

时间:2014-08-16 22:31:41      阅读:237      评论:0      收藏:0      [点我收藏+]

标签:block实现         

block存储区域

这就需要引入三个名词:
● _NSConcretStackBlock
● _NSConcretGlobalBlock
● _NSConcretMallocBlock
正如它们名字说的那样,说明了block的三种存储方式:栈、全局、堆。
【要点1】定义在函数外面的block是global的;另外如果函数内部的block,但是没有捕获任何自动变量,那么它也是全局的。比如下面这样的代码:
typedef int (^blk_t)(int);
for(...){
    blk_t blk = ^(int count) {return count;};
}
虽然,这个block在循环内,但是blk的地址总是不变的。说明这个block在全局段。
【要点2】一种情况在非ARC下是无法编译的:
typedef int(^blk_t)(int);
blk_t func(int rate){
    return ^(int count){return rate*count;}
}
这是因为:block捕获了栈上的rate自动变量,此时rate已经变成了一个结构体,而block中拥有这个结构体的指针。即如果返回block的话就是返回局部变量的指针。而这一点恰是编译器已经断定了。在ARC下没有这个问题,是因为ARC使用了autorelease了。
【要点3】有时候我们需要调用block 的copy函数,将block拷贝到堆上。看下面的代码:
-(id) getBlockArray{
    int val =10;
    return [[NSArray alloc]initWithObjects:
        ^{NSLog(@"blk0:%d",val);},
        ^{NSLog(@"blk1:%d",val);},nil];
}

id obj = getBlockArray();
typedef void (^blk_t)(void);
blk_t blk = (blk_t){obj objectAtIndex:0};
blk();
这段代码在最后一行blk()会异常,因为数组中的block是栈上的。因为val是栈上的。解决办法就是调用copy方法。
【要点4】不管block配置在何处,用copy方法复制都不会引起任何问题。在ARC环境下,如果不确定是否要copy block尽管copy即可。ARC会打扫战场。
注意:在栈上调用copy那么复制到堆上,在全局block调用copy什么也不做,在堆上调用block 引用计数增加


本人用Xcode 5.1.1 iOS sdk 7.1 编译发现:并非《Objective-C》高级编程这本书中描述的那样,看下面代码
int val肯定是在栈上的,我保存了val的地址,看看block调用前后是否变化。输出一致说明是栈上,不一致说明是堆上。
typedef int (^blkt1)(void) ;
-(void) stackOrHeap{
    __block int val =10;
    int *valPtr = &val;//使用int的指针,来检测block到底在栈上,还是堆上
    blkt1 s= ^{
        NSLog(@"val_block = %d",++val);
        return val;};
    s();
    NSLog(@"valPointer = %d",*valPtr);
}
在ARC下>>>>>>>>>>>该block被会直接生成到堆上了。看log: val_block = 11 valPointer = 10
在非ARC下>>>>>>>>>该block还是在栈上的。 看log: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在栈上,还是堆上,布布扣,bubuko.com

block存储区域——如何验证block在栈上,还是堆上

标签:block实现         

原文地址:http://blog.csdn.net/hherima/article/details/38620175

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!