我们在面试的时候经常被问到block,而且也是iOS的特别常见的面试题.比如:
1.block的原理是怎么样的?本质是什么?
2._block的作用是什么?有什么使用注意点?
3.block的修饰词为什么是copy?使用block有哪些使用注意?
4.block在修改NSMutableArray,需不需要添加_block?
接下来带你轻轻松松解读源码,先了解block的本质,我们先创建一个最简单的block如下;
这一个简单的block,我们先用终端把main.m这个文件转成c++代码,我们知道,oc的底层就是c++和c,所以我们利用终端执行下面的操作,把main.m转成c++来看看如下:
接下来我们把main.cpp文件拉到项目开始查看,看一下源码到底是怎么实现的block,打开这个cpp文件,因为main是最后执行的,所以我们直接划到文件的最下面查看如下:
上面的截图一看就是我们刚刚写的那段代码,我们知道变量前面加()一般是强制转换,所以我们可以把上面绿色框框的去掉,看得就比较清晰,剩余如上,最上面的一看就比较简单_main_block_impl_0这个就是创建block的,里面传了2个参数,分别是__main_block_func_0和_main_block_desc这两个东西,而调用block直接就是-->funPtr很大可能就是指针调用,
接下来我们再细看:
这里应该是很容易可以看出它的调用过程了,而上面的1,那个结构体是C++的函数,里面和外面的函数一样,是构造函数,它返回的是结构体本身!
这就是一个很简单的block的调用底层!我们知道block没有这么简单,接下来我们看一个稍微复杂
难度小升级:增加参数如下
然后直接用上面的方法,把这个文件再转成c++文件,结果如下
这个也很清楚,也比较简单,接下来我们难度再升级一点点
难度再小升级:设置一个变量,里面访问,再修改变量,代码如下
这种情况,再没公布结果之前,可能有的同学认为,这个结果是30,也有些人知道是10,但是具体10是怎么来的,我们接下来继续探究,还是生成c++代码看一下
图1由上面的2张图,我们知道,在执行height=30的时候,block里面的height = 10的,这时候赋值30并没有改变block存储的值是10吧?这里是非常明显,所以我们调用block输出的是hello, World:10,结果非常明显,这就涉及到我们有时候面试官说的,你知道block的变量捕获机制吗(capture).
block变量捕获机制(capture)
首先我们先看一张图
我们上面的例子说的是局部变量,其实我们写的int height = 10;其实是auto int height = 10都有这个就省略没写,auto定义的范围就是我们的大括号,我们知道,刚刚说的就是auto的情况就行了,而且auto是值传递.(auto:叫做自动变量,离开作用域就自动销毁)
block捕获:就是block内部会新增一个变量,存储变量的值,这个就叫做捕获.
接下来介绍static情况,请看下图:
static 定义的是指针传递,它的结果是30,和auto修饰的完全不一样,这是怎么回事呢?还是看一下源码解读
先不说源码,我们是不是可以得出一个结论,auto和static修饰的局部变量都是可以被block捕获吧!这个很清楚.而age传递是啥是&age,是传递的age的指针地址啊,赋值什么都是取的是指针地址,我们再看一下取值是啥:
取得也是地址吧!这个就非常清楚,为什么会出现上面的结果!
思考:为什么auto变量不能也设置传递地址呢?
大家可能有这个疑问,接下来,我就写一个例子来说明一下这个情况:
上面的图就解释了这个问题.
而全局变量是直接不捕获,这个大家可以自己证明,按照我上面的方法,应该是非常清晰
到这里,我相信大家对block的变量捕获应该有一个比较本质的认识了!
大家只要知道这个变量是局部的,还是全局的就知道它能不能捕获!
思考:
下面给大家留一个考题,下面的这2种情况block会不会捕获:
test和test1变量会不会捕获???
网友评论