题目一
1 | // 1、实现下面的函数,将 block 的实现修改为 NSLog(@"Hello world"); |
分析:题目的意思很明白,就是要实现一个函数,将作为参数传入的block的实现修改为一句log。有研究过block的结构的都知道,block实际上就是一个接口体。而它的实现部分,是作为函数指针被保存在结构体的invoke
中(即第16个字节处):
1 | struct Block_layout { |
所以这题的解法也很明朗:就是将block结构体中的invoke函数指针地址替换为我们的函数:
1 | // 定义一个函数 |
题目二
1 | // 2.实现下面的函数,将 block 的实现修改成打印所有入参,并调用原始实现 |
分析:这个题目其实和题目一的本质是一样的,都是替换block的实现(即Hook Block),不过,相比较于题目一,这个题的侧重点在于:1、打印所有入参;2、调用原实现。针对这两个问题,我们逐一解析。
1、打印所有入参
对于已知参数个数和参数类型的block,要实现这个,其实并不难,只需要我们再声明替换函数的时候,对应声明参数即可:
1 | //这里要注意的是,第一个参数必须声明为block本身。 |
2、调用原实现
在题目一中,我们仅仅是将invoke的值替换了,也就是说我们舍弃了invoke原本的函数指针地址,即原本的实现;如果我们全局变量,将其先存储,再进行替换,然后在replace_bloke2
函数中调用,是否就达到了目的呢?
1 | //声明一个函数指针,用来存储invoke的值 |