block深入学习

来源:互联网 发布:薪酬数据分析及统计表 编辑:程序博客网 时间:2024/05/07 05:57

block的声明和使用看上一节就行了。
本章主要讲block内部的实现过程及原理。block的定义和函数指针非常相似
对比一下

block定义void (^someBlock)() = ^{//       };函数指针定义void (*functionPionter)() = void functionName(){//内部定义}

当然区别还是有的,block的返回类型可以省略,在block块的结尾有分号。

block也能捕获对象类型,就是在块中使用实例变量。块本身也可以视为对象。对于实例变量,前面不加__block,也能改变其值。

这里写图片描述

块的内部结构

块的底层可以说是函数指针,当然,里面还有其它信息。
这里写图片描述

这是内部结构图。块本身也是对象,在存放块对象的内存区域中,首个变量是指向Class对象的指针,该指针叫isa。和object中的isa是一个意思。

descriptor变量是指向结构体的指针,每个块都包含此结构体,,其中声明了快对象的总体大小,还声明了copy与dispose这两个辅助函数所对应的函数指针,辅助函数在拷贝及丢弃块对象的运行,其中还会执行一些操作,比如说,前者是拷贝对象,后者是将之释放。

在定义块的时候,其中所占的内存区域是分配在栈中的,这就是说,块只在定义它的那个范围内有效,像下面的这种情况就会出现危险。
这里写图片描述

定义在if及else语句中的两个块都分配在栈内存中。编辑器会给每个块分配好栈内存,然后等离开了相应的范围之后,编辑器有可能把分配给块的内存覆盖掉。块在if中有效,但是运行起来,时而正确,时而错误。
为了解决此问题,可以给对象发送copy消息以拷贝,就把块从栈复制到堆内存了,就可以在定义它的范围之外使用。然后块就成带有引用计数的对象了。所以给代码加上两个copy方法调用,就可以解决此问题了。
这里写图片描述

当然了,除了“栈块”和“堆块”之外,还有一类块叫做“全局块”(global block)。这种块不会捕捉任何状态,运行时也无须有状态来参与。块所使用的整个内存区域,在编译期已经完全确定了,因此,全局快可以声明在全局内存里,全局域不可能被系统所回收。这种块相当于单例。下面就是全局快:
这里写图片描述

0 0
原创粉丝点击