zoukankan      html  css  js  c++  java
  • block存储区域——怎样验证block在栈上,还是堆上

    Block存储区域

    首先,须要引入三个名词:
    ● _NSConcretStackBlock
    ● _NSConcretGlobalBlock
    ● _NSConcretMallocBlock
    正如它们名字显示得一样,表明了block的三种存储方式:栈、全局、堆。block对象中的isa的值就是上面当中一个,以下開始说明哪种block存储在栈、堆、全局。block为何是个对象,參考点击打开链接

    ------------【要点1】:全局block------------

    ● 定义在函数外面的block是global类型的
    ● 定义在函数内部的block,可是没有捕获不论什么自己主动变量,那么它也是全局的。比方以下这种代码
    typedef int (^blk_t)(int);
    for(...){
        blk_t blk = ^(int count) {return count;};
    }
    尽管,这个block在循环内,可是blk的地址总是不变的。说明这个block在全局段。注:针对没有捕获自己主动变量的block来说,尽管用clang的rewrite-objc转化后的代码中仍显示_NSConcretStackBlock,可是实际上不是这种。下图能够证明该类型的block是全局的。Xcode5.1.1调试结果

    不管ARC与否上图控制台输出是 <__NSGlobalBlock__: 0x10000f280>,这可能是编译器的优化,本人猜測,没有求证。所以用clang的-rewrite-objc是不准确的。

    ------------【要点2】:栈block--------------

    这样的情况,在非ARC下是无法编译的,在ARC下能够编译
    typedef void (^block_t)() ;
    -(block_t)returnBlock{
        __block int add=10;
        return ^{printf("add=%d
    ",++add);};
    }
    这是由于:block捕获了栈上的add自己主动变量,此时add已经变成了一个结构体,而block中拥有这个结构体的指针。即假设返回block的话就是返回局部变量的指针。而这一点恰是编译器已经断定了。在ARC下能够编译过,是由于ARC使用了autorelease了。
    再说一个场景:

    -(block_t)returnBlock{
        __block int add=10;
        block_t blk_h =^{printf("add=%d
    ",++add);};
        return blk_h;
    }
    block_t bb = [self returnBlock];
    bb();

    这段代码,仅仅是使用了一个自己主动block变量,能够编过,可是造成程序崩溃了。
    假设在返回block的时候加上copy,能够输出正确的数值11

    ------------【要点3】:堆上的block ----------------

    有时候我们须要调用block 的copy函数,将block复制到堆上。看以下的代码:
    -(id) getBlockArray{
        int val =10;
        return [NSArray arrayWithObjects:
            ^{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方法。这样的场景,ARC也不会为你加入copy,由于ARC不确定,採取了保守的措施:不加入copy。所以ARC下也是会异常退出。

    ---------------------【要点4】copy的使用-----------------------------------

    无论block配置在何处,用copy方法复制都不会引起不论什么问题。
    在ARC环境下,假设不确定是否要copy block虽然copy就可以。ARC会打扫战场。
    【注意】:
    ● 在栈上调用copy那么拷贝到堆上
    ● 在全局block调用copy什么也不做
    ● 在堆上调用block 引用计数添加

    ------------------【对《Objective-C 高级编程》的挑战】-----------------------

        笔者用Xcode 5.1.1 iOS sdk 7.1 编译发现:并不是《Objective-C 高级编程》这本书中描写叙述的那样,-rewrite-objc这个命令转化的中间代码,并不可靠。
        block在ARC和非ARC有巨大区别:以下笔者用两种方式来验证:
    1.通过Xcode调试结果,附图
    2.通过变量的地址 int val肯定是在栈上的,我保存了val的地址,看看block调用前后是否变化。输出一致说明是栈上,不一致说明是堆上。
    【第一个方法】,最直观.代码例如以下,非常easy。block捕获了变量val(不管val是否是__block
    -(void) stackOrHeap{
        __block int val =10;
        blkt1 s= ^{
            return ++val;};
        s();
        blkt1 h = [s copy];
        h();
    }
    在非ARC和ARC下,调试结果例如以下:
    能够看到非ARC下一个是stack一个是Malloc。ARC下都是Malloc

    【第二个方法】,声明一个局部变量指针。通过指针来看
    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这样的写变量,两种方式(事实上结果是一样的)

    在ARC下:似乎已经没有栈上的block了,要么是全局的,要么是堆上的
    在非ARC下:存在这栈、全局、堆这三种形式。
  • 相关阅读:
    codeforces 455B A Lot of Games(博弈,字典树)
    HDU 4825 Xor Sum(二进制的字典树,数组模拟)
    hdu 1800 Flying to the Mars(简单模拟,string,字符串)
    codeforces 425A Sereja and Swaps(模拟,vector,枚举区间)
    codeforces 425B Sereja and Table(状态压缩,也可以数组模拟)
    HDU 4148 Length of S(n)(字符串)
    codeforces 439D Devu and Partitioning of the Array(有深度的模拟)
    浅谈sass
    京东楼层案例思维逻辑分析
    浅谈localStorage和sessionStorage
  • 原文地址:https://www.cnblogs.com/zfyouxi/p/4237261.html
Copyright © 2011-2022 走看看