iOS 知识点程序员程序猿阵线联盟-汇总各类技术干货

JSPatch是如何实现动态创建block的

2018-02-05  本文已影响69人  皮拉夫大王在此

最近在项目中遇到了一个问题,如何动态创建一个block呢?提到动态创建,大家可能更多想到的是OC方法,但是block能否能像OC方法一样动态添加呢?为了解决这个问题我们首先要了解OC的block到底是什么,只有弄清楚什么block的结构才能谈及动态创建。

block的结构

block是对象,OC中对象的本质上是结构体,因此block实际上是一个结构体,在Clang 7 documentation中有对block的详细描述:

block 结构

先来看几个比较重要的内容:

首先是void (*invoke)(void *, ...),这是一个函数指针,它是block所执行代码的地址,也就是说block之所以能像函数一样执行都是因为有了这个函数指针,它的第一个参数是固定的,从第二个参数位置起才是block真正的参数。这一点很像OC的方法,OC的方法从第3个参数位置起才是真正的参数,前两位分别是self和cmd。而block的第一个参数猜测很可能是block自己的地址。

void (*copy_helper)(void *dst, void *src); 是blcoK在拷贝时的回调,也就是说block在执行拷贝操作时我们可以拿到拷贝前和拷贝后的block。

void (*dispose_helper)(void *src);是block在将被销毁时的回调。

const char *signature;是block的签名,这个签名类似OC方法的签名,它描述了block的返回值、参数信息。

如何生成block?

因为block本身就是个结构体,那么是否意味我们创建一个与block结构一样的结构体,然后对这个结构体相应进行赋值是不是就可以达到创建block的目的了呢?实际上JSPatch就是这样创建block的。JSPatch的关键方法如下:

JSPatch创建block代码+注释

JSPatch主要通过以上6步骤实现了动态生成block。我们在生成block时的思路与此类似,但是由于之前没有注意到void (*dispose_helper)(void *src);的用途,采用了另一种方式来管理内存。虽然最终纠正过来了,但是还是值得一提的:当我们将生成的block返回给外界时,实际上block的生命周期已经不归我们管理了,如果拿不到block的释放时机(实际上是可以拿到的)的话,那么怎么感知到block被释放了呢?在这里我们借助了关联引用

借助关联引用解决感知生命周期

首先创建了一个自定义类PhoiexFlagObject,并在PhoiexFlagObject的delloc方法中实现相关内存清理工作,此时如果外界的block释放时会对对象flagObject做一次release操作,flagObject触发delloc,这样我们就能拿到返回给外界的block释放时的时机了。文章相关libffi内容可以参考jiayoubaobao的相关文章。

上一篇 下一篇

猜你喜欢

热点阅读