我爱编程

05进阶之路-Block

2018-05-31  本文已影响45人  进击的iOS开发

1. Block本质

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

image

2. Block数据结构:

学习链接
通过clang编译成C++代码可以看出,其数据结构

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

image
ARC下这是局部变量添加__block的数据结构
image
会把__block修饰的对象封装到一个结构体里面。

3. __block的原理

image

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


image

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


image

4. Block截获变量的特性

局部普通变量:截获其值
局部对象变量:连同所有权修饰符一起截获
局部静态变量:以指针的形式截获
全局变量/全局静态变量:不截获

5. Block的内存管理

对不同类型的Block进行操作结果


image

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


image

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;
上一篇 下一篇

猜你喜欢

热点阅读