1. Block本质
学习链接
封装了函数及其上下文的对象(说是对象是其有ISA指针)。或者带有自动变量值的匿名函数
有三种类型:
栈区Block:MRC下的Block是在栈区的(用copy到堆区),只在他的作用域有效
堆区Block:MAR下用copy。ARC自动copy到堆区。
全局Block:当一个block在闭包中不捕获程序的任何上下文(如各种程序中的变量)时,编译器在编译阶段就能够知道这个block执行的所需要的所有信息,这时,block会当做全局变量保存在全局内存中,以相当于单例的形式存在,它将不会收到任何release消息。这是编译器的一个优化点,减少了当block被copy或销毁时的多余操作。

2. Block数据结构:
学习链接
通过clang编译成C++代码可以看出,其数据结构
ARC下这是局部变量不加__block的数据结构

ARC下这是局部变量添加__block的数据结构

会把__block修饰的对象封装到一个结构体里面。
3. __block的原理

说是对象因为有isa指针,每次做操会赋值会拿到该类的__forwarding指针,在拿到该实际值,如果在栈上,__forwarding指向自己

如果发生了copy操作,将会在堆上创建一个副本,栈上的__forwarding指针指向堆区的。堆区的指向自己。保证只用一个数据操作,也保证了堆区保存,不至于作用域结束无法访问。

4. Block截获变量的特性
局部普通变量:截获其值
局部对象变量:连同所有权修饰符一起截获
局部静态变量:以指针的形式截获
全局变量/全局静态变量:不截获
5. Block的内存管理
对不同类型的Block进行操作结果

为啥要对block进行copy操作呢,因为block一般都在栈区,使用的时候栈区的block早就销毁了,要啥自行车。copy到了堆区,就不用担心销毁了,注意循环引用,注意销毁(ARC自动销毁)

6. Block 引发的循环引用
Block 也是对象,会强引用所用到的类,是循环引用的高发地带,还是解除循环引用的两种方法。用weak避免发生循环引用,或者手动断环的方式,手动断环也有两种方式,分为“内断环”和“外断环”,我个人推荐“外断环”,因为“内断环”如果block得不到调用就会产生内存泄漏。
block *bl = [block new];
bl.cancelBlock = ^{
bl.aa = @"";
};
//外断环
bl.cancelBlock = nil;
bl = nil;
------------------------
__block block *bl = [block new];
bl.cancelBlock = ^{
bl.aa = @"";
//内断环
bl.cancelBlock = nil;//或者 bl = nil;
};
// 必须得执行,不执行的话会导致内存泄漏
bl.cancelBlock();
bl = nil;
网友评论