美文网首页
我所理解的Block:3、Block的存储区域

我所理解的Block:3、Block的存储区域

作者: 杨淳引 | 来源:发表于2016-09-16 14:54 被阅读435次

    23、在前文中的例子中,Block结构体里的isa指针还没有详细讲解,这个指针都被置向了_NSConcreteStackBlock,它标识了Block的类型。
    其实除了_NSConcreteStackBlock这个类型外,Block还有其他的类型,这些类型总共有3种:
    (1)、_NSConcreteStackBlock
    (2)、_NSConcreteMallocBlock
    (3)、_NSConcreteGlobalBlock

    24、这3种类型分别表示了Block对象存储的区域,如下图:


    25、编译器的模式也会影响到Block对象的存储,同一个Block对象在ARC模式下和在MRC模式下可能会存储在不同的区域。接下来,就使用代码来研究一下在ARC模式下和在MRC模式下,全局Block、普通Block、截获变量的Block和截获可变变量的Block分别是怎么存储的。

    26、可以通过打印出Block对象来确定它存储的位置,这3种类型的Block对象打印出来的类分别是:
    (1)、__NSStackBlock__
    (2)、__NSMallocBlock__
    (3)、__NSGlobalBlock__

    普通全局Block

    27、首先在ARC模式下,编写一个全局普通Block,并分别打印出持有这个Block对象的变量,和这个变量的复制值:



    可以发现,两种情况下打印出来的Block对象都是__NSGlobalBlock__类的,说明它们都存储在.data区。

    28、试一下在MRC模式下执行相同的代码:



    发现效果相同。说明,<b>普通全局Block在ARC模式下和MRC模式下的存储区域是一样的,都是.data区。</b>

    截获变量的全局Block

    29、全局Block能截获的变量,只能是全局变量(不可能获取到局部变量)。而全局变量在Block中本身就是可变的了,所以“截获变量的全局Block”就相当于“截获可变全局变量的全局Block”。

    30、编写以下代码,在ARC模式下执行:



    在MRC模式下也执行相同代码:



    从执行结果可以看出,截获了变量的全局Block存储区域和普通全局Block是一样的。这说明了,<b>全局Block都是__NSGlobalBlock__类的,存储在.data区。</b>

    普通Block

    31、对于普通Block,编写以下代码来查看它的存储区域,在ARC模式下分别打印出持有普通Block的变量、持有普通Block的变量的复制值、普通Block对象和普通Block对象的复制值:



    再在MRC模式下也执行相同代码:



    从打印结果可以看出:<b>不论是在ARC模式下还是在MRC模式下,不截获变量的普通Block都是当作__NSGlobalBlock__类对象处理的,存储在.data区。</b>
    还有一点需要注意:前文在使用clang命令转换普通Block的时候,Block对象的isa指针是指向_NSConcreteStackBlock的,说明普通Block本质上是__NSStackBlock__类的;而在此处通过打印可知,因为没有截获变量,编译器实际上就将普通Block当做__NSGlobalBlock__类来处理了。

    截获变量的Block

    32、上文演示的几种Block在不同编译器模式下存储区域并没有差别,接下来的Block就开始有差别了。
    编写以下代码,在ARC模式下分别打印出持有截获变量Block的变量、持有截获变量Block的变量的复制值、截获变量的Block对象和截获变量的Block对象的复制值:



    然后在MRC模式下执行相同代码,查看结果:



    比较两种模式下的打印结果,可以发现:
    (1)、在MRC模式下,截获变量的Block对象本身是存储在栈上的,即使通过持有这个Block对象的变量来访问它,仍然能顺利访问到存储在栈上的Block对象。只有主动调用copy方法,才能将Block对象从栈上复制到堆上;
    (2)、在ARC模式下,截获变量的Block对象本身也是存储在栈上的,只是当使用持有这个Block对象的变量来访问它时,这个Block对象就会被从栈上复制到堆上,这样变量访问到的就是存储在堆上的Block对象了。如果主动调用copy方法,Block对象也会被赋值在堆上;

    (3)、比较两种模式下的区别,可以发现在使用变量访问Block对象的情况下,在不同编译器模式下Block对象的存储区域是不同的。所以才会有ARC模式下没有_NSConcreteStackBlock这种说法。

    截获可变变量的Block
    33、再来看一看最后一种Block,编写以下代码,在ARC模式下分别打印出持有截获可变变量Block的变量、持有截获可变变量Block的变量的复制值、截获可变变量的Block对象和截获可变变量的Block对象的复制值:



    然后在MRC模式下执行相同代码,查看结果:



    可以发现,情况和截获变量的Block一样,都是在使用变量访问Block对象的情况下,在不同编译器模式下Block对象的存储区域不同。那么可以得出以下结论:
    (1)、<b>在不同编译器模式下,截获变量的Block本身都是存储在栈上的;</b>
    (2)、<b>使用变量访问这种Block时,MRC模式下能访问到栈上的对象,ARC模式下访问到的是被复制到堆上的对象。</b>

    相关文章

      网友评论

          本文标题:我所理解的Block:3、Block的存储区域

          本文链接:https://www.haomeiwen.com/subject/afkiettx.html