![](https://img.haomeiwen.com/i7911324/4293b853941828a6.jpg)
一、Block本质
1.1、概念
Block是将函数及其执行上下文封装起来的对象。
问题1:什么是Block?
Block是将函数及其执行上下文封装起来的对象。
![](https://img.haomeiwen.com/i7911324/9ae3d6f928b48fc6.jpg)
问题2:什么是Block调用?
Block调用就是函数调用。
1.2、代码转换指令
![](https://img.haomeiwen.com/i7911324/cb1e05a72ec53d1d.jpg)
二、Block截获变量
问题2:截获变量面试题
![](https://img.haomeiwen.com/i7911324/ae1029d7c58b9212.jpg)
答案是12。
2.1、截获变量类型分类
![](https://img.haomeiwen.com/i7911324/17865bbccfeabbff.jpg)
![](https://img.haomeiwen.com/i7911324/3e570cd25dfd9886.jpg)
问题3:关于Block的截获变量特性怎么理解?
从截获类型和截获特性进行解释(见上图)。
三、__block修饰符
3.1、赋值和使用的区别
使用
不需要使用__block
![](https://img.haomeiwen.com/i7911324/909b11ecc7d58bc2.jpg)
赋值
需要使用__block
![](https://img.haomeiwen.com/i7911324/a55fa99bebdf9061.jpg)
3.2、使用场景细分
问题4:什么场景使用__block修饰符?
![](https://img.haomeiwen.com/i7911324/dd7d403ad654d0bc.jpg)
![](https://img.haomeiwen.com/i7911324/481afb1ac47beda9.jpg)
![](https://img.haomeiwen.com/i7911324/2dabe6c8968a6af2.jpg)
问题5:__block笔试题
![](https://img.haomeiwen.com/i7911324/91ff30240c2b135c.jpg)
解释原因:
1、__block修饰的变量变成了对象,如下:
![](https://img.haomeiwen.com/i7911324/14172668a08f7f47.jpg)
2、后面使用的multiplier都是结构体里面的,通过forwarding指针引用,如下:
![](https://img.haomeiwen.com/i7911324/ef32ff4b0e3cf9b4.jpg)
3、又因为在Block在栈上,__block的forwarding指针指向自己,如下图:
![](https://img.haomeiwen.com/i7911324/cafddd5d24a2ca1b.jpg)
4、所以这里修改的multiplier也就是修改栈上的变量。而Block在栈上,所以使用的也是栈上的变量。
补充:__block在ARC和MRC区别
- MRC 环境下,block 截获外部用 __block 修饰的变量,不会增加对象的引用计数
- ARC 环境下,block 截获外部用 __block 修饰的变量,会增加对象的引用计数
四、Block内存管理
4.1、Block类型
![](https://img.haomeiwen.com/i7911324/a822c2732753fb73.jpg)
4.2、Block内存区域
![](https://img.haomeiwen.com/i7911324/7a2297282c6ea260.jpg)
4.3、Block的Copy操作
![](https://img.haomeiwen.com/i7911324/5a19b92dc6549a6e.jpg)
注意:
对Block的Copy操作理解,会将Block从栈放到堆上,防止使用的时候,Block被销毁。
所以,一般声明的Block成员变量关键字是Copy。
4.4、栈上Block的销毁
![](https://img.haomeiwen.com/i7911324/fcb2f2b4fa33c2b8.jpg)
4.5、栈上Block的Copy
问题6:当把栈上的Block进行Copy操作之后,在MRC环境下,是否会引起内存泄漏?
是的
4.6、栈上__block变量的Copy
![](https://img.haomeiwen.com/i7911324/2e78cf8d5930e969.jpg)
所以一旦被Copy到堆上,即使代码表面上是修改栈上的__block变量,其内在本质是修改堆上的__block变量。
例题实战
![](https://img.haomeiwen.com/i7911324/4397821a2c747c6b.jpg)
- _blk进行了Copy操作,里面的multiplier用的是堆上的。
- multiplier = 6其实是通过栈上的forwarding修改堆上的multiplier。
- 结果是 4 * 6 = 24。
4.7、forwarding指针总结
![](https://img.haomeiwen.com/i7911324/eb260fb043f9c83c.jpg)
- 如果没有对__block进行Copy操作,就是操作栈上的__block变量。
- 如果发生了Copy操作,无论是在栈上还是在堆上,都是操作堆上的__block变量。
五、Block循环引用问题
问题7:以下代码有什么问题?
![](https://img.haomeiwen.com/i7911324/0c1ba73e3f212b51.jpg)
有循环引用。
原因:
- 根据Block截获变量的特性,对于对象,会将所有权修饰符一起截获。
- 这里对象持有Block,又因为array是strong,所以Block对array也是strong。
解决办法:
![](https://img.haomeiwen.com/i7911324/d1fb111917db5b04.jpg)
- 也是从截获变量特性解释
问题8:以下代码有问题吗?
![](https://img.haomeiwen.com/i7911324/273fa364c27021df.jpg)
答案:
![](https://img.haomeiwen.com/i7911324/bf675fd2a59dd0c7.jpg)
解释:
在ARC情况下
![](https://img.haomeiwen.com/i7911324/75db981cf182bd9e.jpg)
解决办法:
![](https://img.haomeiwen.com/i7911324/4c9f6a3dad446ccc.jpg)
问题9:为什么Block会产生循环引用?
从截获变量特性进行答题
问题10:怎样理解Block截获变量对特性?
![](https://img.haomeiwen.com/i7911324/09648dcd80e5c7ca.jpg)
问题11:你遇到过哪些循环引用?你又是怎样解决的?
- NSTimer
- Block
网友评论