block的底层实现

来源:互联网 发布:godaddy转阿里云 编辑:程序博客网 时间:2024/04/28 00:35

1、我们都会使用 block ,但是它真正是如何工作的呢?换句话说block的本质是什么?
看下列实例,想想程序的结果:

int main(int argc, const char * argv[]) {     int a = 10;    __block int b = 20;     void (^block)() = ^(){         printf("a = %d\n",a);         printf("b = %d\n",b);     };    a = 50;    b = 30;    block();

程序的结果是: a = 10 , b = 30;

这个结果可能大家都知道 ,那么为什么会出现这样的情况呢?很多人都会说 ,b前面加了__block所以他的值可以改变 ,a没加所以不能改变 。这只是表象,接下来我们就研究一下他的block的本质。

2、探究block的底层原理,打开终端 ,把目录切换到当前main.m所在的路径下,我们需要把这个 main.m 文件 编程成c++ 的文件 main.cpp.
输入终端命令: clang -rewrite-objc main.m
生成一个main.cpp文件 ,打开它,但是你要做好心理准备,这个 文件十万多行。

3、找到下列代码

int main(int argc, const char * argv[]) {     int a = 10;    //__attribute__((__blocks__(byref))) __Block_byref_b_0 b = {(void*)0,(__Block_byref_b_0 *)&b, 0, sizeof(__Block_byref_b_0), 20};     void (*block)() = &__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, a, (__Block_byref_b_0 *)&b, 570425344);    a = 50;    (b.__forwarding->b) = 30;    ((void (*)(__block_impl *))((__block_impl *)block)->FuncPtr)((__block_impl *)block);    return 0;}}

分析:
3.1、分析这个block参数
&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, a, &b, 570425344)

//block -> 实质 函数指针
//__main_block_func_0 指针
//__main_block_desc_0_DATA 地址 block 的描述数据
//a 普通变量
//&b b地址 b -> __Block_byref_b_0类型
//b 变量 就会被封装成 __Block_byref_b_0 结构体类型

3.2、分析struct __Block_byref_b_0 结构体

 struct __Block_byref_b_0 {        void *__isa;  //当前对象的指针        __Block_byref_b_0 *__forwarding; //当前这种结构体类型的指针 __forwarding存对象自己地址        int __flags; //标记        int __size; //结构体的大小        int b; //变量    };

3.3、函数的初始化

 struct __main_block_impl_0 {        struct __block_impl impl;        struct __main_block_desc_0* Desc;        int a; //  10        __Block_byref_b_0 *b; // by ref        __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int _a, __Block_byref_b_0 *_b, int flags=0) : a(_a), b(_b->__forwarding) {            impl.isa = &_NSConcreteStackBlock;            impl.Flags = flags;            impl.FuncPtr = fp;  //执行的那段代码 打印            Desc = desc;        }    }

3.4、__block_impl结构体分析

 struct __block_impl {        void *isa;        int Flags;        int Reserved;        void *FuncPtr;    };

3.5、__main_block_func_0

 __main_block_func_0(struct __main_block_impl_0 *__cself) {        //地址 直接访问属性        __Block_byref_b_0 *b = __cself->b; // bound by ref        int a = __cself->a; // bound by copy        printf("a = %d\n",a);        printf("b = %d\n",(b->__forwarding->b));    }

在上述的代码中我们可以理解为: 变量a传入的是值,变量b传入的是地址。__block 把b强转成一个结构体指针。

blcok的本质就是一个函数指针 ,也可以说是一个指向结构体的指针。

0 0
原创粉丝点击