美文网首页
理解Block

理解Block

作者: 氺_氺 | 来源:发表于2018-07-20 11:14 被阅读0次

    一、block其实是有类型的, 且一共有3种类型, 全局块, 栈块, 堆块:

    1.__NSGlobalBlock__: 存储在全局/静态的 block,不会捕获任何外部变量。

    2.__NSStackBlock__: 存储在栈中的 block,当函数返回时会被销毁。

    3.__NSMallocBlock__: 存储在堆中的 block,当引用计数为0时会被销毁。

    二、由于ARC已经能很好地处理对象的生命周期的管理, 所以都放到堆上管理, 不在使用栈块管理了, 所以就没有栈块的。而且捕获了变量的block默认会分配在栈区, 在MRC中需要保留的话, 可以手动改到堆区; 在ARC中, block也是在栈区的, 但编译器会并自动将其copy到堆中, 所以会存储在堆区。ARC下编译器自动copy当前block至堆区的过程。默认分配在栈上的block, 如果其所属的作用域结束, 该block就被释放, 当然, block中的所有变量也会被释放。为了解决栈块在其变量作用域结束之后被释放的问题,我们需要把block copy到堆中,延长其生命周期。在开启ARC时,编译器会判断其是不是全局块, 若不是全局块则需要将block从栈copy到堆中,并自动生成相应代码。这样, 栈中的block就可以释放了, 我们可以通过堆中的block来继续进行一系列操作。

    三、对于block捕获的变量, block默认是将其复制到其数据结构中来实现访问的, 且block捕获的变量是在block内部进行修改是不会影响外部变量的。 __block 其实提升了变量的作用域。

    当使用__block修饰后, 在block内部便可以修改捕获的变量了。在ARC下, block内部和block后的地址是相同的都存在于堆中, 且与block前的地址不同。在MRC下, block前, block后与block内部的地址是相同的, 且都是在栈中的。

    四、__weak 本身是可以避免循环引用的问题的,但是其会导致外部对象释放了之后,block 内部也访问不到这个对象的问题,我们可以通过在 block 内部声明一个 __strong 的变量来指向 weakObj,使外部对象既能在 block 内部保持住,又能避免循环引用的问题;__block 本身无法避免循环引用的问题,但是我们可以通过在 block 内部手动把 blockObj 赋值为 nil 的方式来避免循环引用的问题。另外一点就是 __block 修饰的变量在 block 内外都是唯一的,要注意这个特性可能带来的隐患;但是__block有一点:这只是限制在ARC环境下。在非arc下,__block是可以避免引用循环的

    (图1)arc下对普通变量进行测试 (图2)arc下对对象变量测试

    五、闭包的通俗理解:

    计算机语言中、“闭包(Closure)是由函数和与其相关的引用环境组合而成的实体” 。闭包就是能够读取其他函数内部变量的函数。例如在javascript中,只有函数内部的子函数才能读取局部变量,所以闭包可以理解成“定义在一个函数内部的函数“。在本质上,闭包是将函数内部和函数外部连接起来的桥梁。Block就是OC对闭包的实现。

    六、文章摘抄于以下的文章,如需要获取更详细的知识点的话,请仔细阅读以下文章:

    1、CD蜗牛的博客《浅谈block实现原理及内存特性之一: 内部结构和类型》

    2、CD蜗牛的博客《浅谈Block实现原理及内存特性之二: 持有变量》

    3、CD蜗牛的博客《浅谈Block实现原理及内存特性之三: copy过程分析》

    4、一缕殇流化隐半边冰霜《深入研究Block捕获外部变量和__block实现原理》

    5、纠结的哈士奇《__weak与__block区别,深层理解两者区别》

    相关文章

      网友评论

          本文标题:理解Block

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