Block实现-block存储域

Posted 故园的梨花

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Block实现-block存储域相关的知识,希望对你有一定的参考价值。

Block转换为Block的结构体类型的自动变量,_block变量转换为_block变量的结构体类型的自动变量,所谓结构体类型的自动变量,即栈上生成的该结构体的实例。我们已经了解了block时oc对象,该block的类为_NSConcereteStackBlock,虽然该类并没有出现以变换源代码中,还有很多类似的类

_NSConcereteStackBlock    对象存储域在栈上

_NSConcereteGlobalBlock     域全局变量一样,设置在程序的数据区域(.data中)

_NSConcereteMallocBlock   设置在malloc函数分配的内存(堆上)块中。

下面我们介绍一下一个应用程序的内存分配

并非不是所有的block都是NSConcereteStackBlock,但是事实并不是这样的,在记述全局变量的地方使用Block语法时,生成的block为_NSConcereteGlobalBlock类对象。

#import <Foundation/Foundation.h>
void(^blk)(void)=^{printf("Block");};
int main() {
    blk();
    return 0;
}

将上面源代码进行转换之后得到结果:

struct __blk_block_impl_0 {
  struct __block_impl impl;
  struct __blk_block_desc_0* Desc;
  __blk_block_impl_0(void *fp, struct __blk_block_desc_0 *desc, int flags=0) {
    impl.isa = &_NSConcreteGlobalBlock;
    impl.Flags = flags;
    impl.FuncPtr = fp;
    Desc = desc;
  }
};

 

我们可以清晰的看到这里的block是全局变量,因为在全局变量的地方不能够使用局部变量,由此可以得知此结构体实例不依赖任何执行时候的状态,所以整个程序只需要一个实例,即使在函数内而不是记述广域变量的地方使用block语法时,之遥block不截获自动变量,就可以将block用结构体设置在程序的数据区域。

在出现一下两种方式的时候,block是_NSConcereteGlobalBlock 类对象

1 记述全局变量的地方使用block语法

2 block语法的表达式中不使用应截获的自动变量的时候。

 

除此之外的block都要配置在栈上。那么现在问题就来了,我们什么时候使用_NSConcereteMallocBlock,总不能不用,这正是为了解决下面两个问题,

1 Block超出变量作用域但是却可存在。

2 _block变量用结构体成员变量_fowarding存在的原因。

我们需要了解,配置在全局变量上的block在变量作用域外也可以安全的访问,但是配置在栈上的,如果其所属的变量作用域结束,该block就被遗弃,所以Blocks提供了将栈上的block复制到堆上,这样即使block语法记述的变量作用域结束,堆上的block还可以继续存在。

_block变量存储域

需要注意的是,将栈上的_block变量用结构体实例在_block变量从栈上复制到堆上的时候,会将成员变量的_forwarding的值替换为复制目标的堆上的_block变量的结构体实例的地址。

以上是关于Block实现-block存储域的主要内容,如果未能解决你的问题,请参考以下文章

__block变量存储域

__block变量存储域

ios block和delegate的区别

为什么Block超出变量作用域还可以继续存在?

__block 说明符的作用以及其对Clang编译器的影响

Block内存管理实例分析