c语言block内部的实现原理,Block原理分析详解

1 基本说明

Block一直是OC的一个重点、难点、黑科技。Block在日常项目中经常使用,他的实现方式和一般的oc代码不一样。同时也很容易出现使用不慎的情况。我们知道OC的本质是C语言+runtime。runtime中的具体实现完全就是汇编加上C语言。而且我们发现大部分都是通过结构体实现的。我们可以通过clang -rewrite-objc main.m这种命令把包含Block的main.m函数反编译(注意:这里所说的反编译并不是真正的反编译,只是把OC源码转换为对等的C++源码)为为C++的具体实现。下面我就会通过这个命令来分析一下Block转换以后的源码。下面所有列子中转换前的代码都在main.m中,替换后的代码都在mainX.cpp中.

2 void (*block)(void)类型解析

我们先看一下转换以前的代码。顶一个一个block。只定义一个变量i并且赋值为1。对应的文件为mainX.cpp。

int main() {

void (^blk)(void) = ^(){

int i = 1;

};

blk();

return 0;

}

下面是转换以后的代码。

struct __block_impl {

void *isa;

int Flags;

int Reserved;

void *FuncPtr;

};

static void __main_block_func_0(struct __main_block_impl_0 *__cself) {

int i = 1;

}

struct __main_block_impl_0 {

struct __block_impl impl;

struct __main_block_desc_0* Desc;

__main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int flags=0) {

impl.isa = &_NSConcreteStackBlock;

impl.Flags = flags;

impl.FuncPtr = fp;

Desc = desc;

}

};

static struct __main_block_desc_0 {

size_t reserved;

size_t Block_size;

} __main_block_desc_0_DATA = { 0, sizeof(struct __main_block_impl_0)};

int main() {

void (*blk)(void) = ( (void (*)()) & __main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA) );

((void (*)(__block_impl *))((__block_impl *)blk)->FuncPtr)((__block_impl *)blk);

return 0;

}

上面是我截取的关键部分源码,其他还有很多辅助性的代码,这里我们就不用管了。看这段代码我们发现一个简单的block的转换成C++以后增加了很多代码:

main函数入口,我们可以发现这个函数里面主要初始化了一个__main_block_impl_0的结构体。并且调用结构体的FuncPtr方法。

__main_block_impl_0结构体。这个结构体有一个__block_impl和__main_block_desc_0结构体。以及一个初始化函数。

__block_impl结构体。这个结构体有四个变量。其中我们可以发现有两个很关键的isa和FuncPtr。

__main_block_desc_0结构体。这个结构体包含了两个size_t类型的属性,主要用于记录Block的内存大小。

__main_block_func_0静态方法,我们发现这个方法就是BLock的具体实现。

2.1具体流程分析

首先main函数代码。

int main() {

void (*blk)(void) = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA));

((void (*)(__block_impl *))((__block_impl *)blk)->FuncPtr)((__block_impl *)blk);

return 0;

}

我们把它具体简化以后如下:

struct __main_block_impl_0 tmp = __main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA);

struct __main_block_impl_0 *blk = &tmp;

(*blk->impl.FuncPtr)(blk);

1首先初始化一个__main_block_impl_0结构体变量。并且传入的参数是__main_block_func_0指向结构体的具体实现。__main_block_desc_0_DATA是__main_block_desc_0结构体的一个变量,主要目的是指定结构体的大小。

2 把tmp的地址赋值给blk指针。

3 通过blk找到他的impl属性,然后再通过impl这个__block_impl变量获取FuncPtr函数的地址。然后传入blk的指针作为参数。从而实现OC中的blk();这句话。

接下来我们看一下__main_block_impl_0这个结构体。

struct __main_block_impl_0 {

struct __block_

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值