block

作者: Yuann | 来源:发表于2017-06-12 14:18 被阅读0次

    block的本质,实际上是[带有自动变量值的匿名函数],block的不安全,除了循环引用,99%的崩溃都是因为你没有给block判空,其他问题,都是因为循环引用.

    block的真正结构:
    struct Block_descriptor_1{
    uintptr_t reserved;
    uintptr_t size;
    }
    struct Block_layout{
    void isa;
    volatitle int32_t flags;
    int32_t reserved;
    void(
    invoke)(void *,...);
    struct Block_descriptor_1 descriptor;
    }
    在objc中,根据对象的定义,凡是首地址是
    isa的结构体指针,都可以认为是对象(id),这样在objc中,block实际上就算是对象.
    那么既然block是个对象,name就应该有Class,那么block的class是什么呢?

    在block runtime中,定义了6中类
    _NSConctreteStackBlock 栈上创建block
    _NSConctreteMallocBlock 堆上创建的block
    _NSConctreteGlobalBlock 作为全局变量的block
    _NSConctreteWeakBlockVariable
    _NSConctreteAutoBlock
    _NSConctreteFinalizingBlock

    全局block
    在编译完成后,block内部的代码将会提取出来,成为一个单独的C函数,创建block时,实际上就是在方法中声明一个struct,并且初始化该struct的成员,而执行block时,就是调用那个单独创建的c函数,并把struct指针传递过去,block的实际效果,相当于C语言中的匿名函数
    于是就可以理解_NSConctreteGlobalBlock的使用了,因为全局block是当一个block内部没有捕获任何外部变量时,就会是一个全局block类,此时,这个block与一个函数无异,所以那么他就应该和函数一样的静态特性,而且,我们在调用block的时候,其实和普通的c函数的调用很相似,都是名称家括号:block()
    那么有函数一样静态特性的block,显然不需要再去考虑其他的生命周期

    栈block
    这个类型的block,是在编译器发现block内部引用了外部变量后,会生成的block类型.
    在block内部有引用外部变量时,当struct第一次被创建时.他是存在于该函数的栈帧上的,其Class是固定的_NSConcreteStackBlock,其捕获的变量是会赋值到结构体成员上,所以当block初始化完成后,捕获到的变量不能更改

    当函数返回时,函数的栈帧被销毁,这个block的内存也会被清除,所以在函数结束后仍然需要这个block是,就必须用Block_copy()方法将它拷贝到堆上,这个方法的核心动作很简单:申请内存,将栈数据复制过去,将Class改一下,最后向捕获到的对象发送retain,增加block的引用计数,
    之所以这样设计,实际上,可以认为,当block有了外部变量的捕获,那么他就需要持有这个外部变量,就是赋值到结构体成员上,这种捕获,造成了block对应struct结构体大小的动态变化,所以设计上适合放在栈上更合理

    堆block
    在栈block中,说到过,当函数栈帧销毁,那么栈block也会被随之清除,但是我们一般都需要在函数结束后仍然能使用block,所以需要把block拷贝到堆上,在copy时,就把栈block的类型转成了堆block

    所以在mrc时代,block的属性关键字必须是copy,这样就可以保证在给block属性赋值的时候,能把栈上的block给copy都堆区

    为什么要把block放到堆区才安全

    block是个匿名函数,只不过我们给了一个变量来引用这个匿名函数,在需要的时候调用,但是栈block就会随着函数栈帧的销毁而销毁,这样一来,我们之前做引用的变量再去调用一块被销毁的内存,就会出现内存崩溃

    所以只有把block放到由我们来控制生命周期的堆区中,才能安全的使用block
    我们知道在oc中,对象都会在堆区存储,实际上,此时的堆block,他的确就是一个对象,而且你还需要对他手动release,当然在arc下,这就不同了

    arc下的block

    全局block
    没有捕获任何外部变量,所以他是一个全局block,

    堆block和栈block
    只要一个block被赋值给一个strong变量,就会自动copy,那么就得到了堆block````

    相关文章

      网友评论

          本文标题:block

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