Block的内部实现原理
来源:互联网 发布:虚拟机网络连接模式 编辑:程序博客网 时间:2024/05/20 03:04
抛砖引玉
先给出问题,大家思考下结果吧,如果分别调用以下两个方法,结果如何?
void blockFunc1(){ int num = 100; void (^block)() = ^{ NSLog(@"num equal %d", num); }; num = 200; block();}
void blockFunc2(){ __block int num = 100; void (^block)() = ^{ NSLog(@"num equal %d", num); }; num = 200; block();}
答案是
blockFunc1 : num equal 100blockFunc2 : num equal 200
是不是有人答错了?再来两个函数。这两个的结果与blockFunc2一样,打印出来的 num 为 200
// 全局变量int num = 100;void blockFunc3(){ void (^block)() = ^{ NSLog(@"num equal %d", num); }; num = 200; block();}
void blockFunc4(){ static int num = 100; void (^block)() = ^{ NSLog(@"num equal %d", num); }; num = 200; block();}
疑问:
我们发现num做为局部变量时加上 _ _block 修饰符、num做为全局变量以及num为静态局部变量时在block中输出结果是一样的,皆为被修改之后的值,而做为局部变量并且未加上__block的num在block中输出的值却还是未赋值之前的值。这是为什么呢?探索这个问题我们就需要看看底层结构是如何实现的了
探索内部原理
Objective-C是一个全动态语言,它的一切都是基于runtime实现的!在运行时会将OC转换成C,我们可以利用这个来查看关于block在内部是如何实现的
新建一个Command Line Tool项目,将以上代码放入main.m中,如图
这里我们打开终端,cd到项目目录下,然后将用下面的命令将OC重写为C
clang -rewrite-objc main.m
这时我们可以发现当前目录下多了一个main.cpp文件,打开它并滚到最下面
这里我们可以看到blockFunc1的C语言实现方法
void blockFunc1(){ int num = 100; void (*block)() = ((void (*)())&__blockFunc1_block_impl_0((void *)__blockFunc1_block_func_0, &__blockFunc1_block_desc_0_DATA, num)); num = 200; ((void (*)(__block_impl *))((__block_impl *)block)->FuncPtr)((__block_impl *)block);}
去掉类型转换
void blockFunc1(){ int num = 100; // *************************重点句*********************** void (*block)() = &__blockFunc1_block_impl_0(__blockFunc1_block_func_0, &__blockFunc1_block_desc_0_DATA, num)); // ***************************************************** num = 200; ((void (*)(__block_impl *))((__block_impl *)block)->FuncPtr)((__block_impl *)block);}
这里我们可以看到
block实际上是指向结构体的指针
该结构体为
我们来看下带__block的blockFunc2
在 blockFunc1 中,block指向了一个名为blockFunc1_block_impl_0的结构体,并且在初始化时输入了三个参数(blockFunc1_block_impl_0最后的flags有默认参数,所以可以不用传参),第三个参数就是我们写的num,与blockFunc2相比较,这里的num并没有带*号,所以说在这里它只是传值而非传址,而下面的【num = 200;】也就没什么卵用了。这就是blockFunc2、blockFunc3与blockFunc4为什么能打印出num改变后的值,而blockFunc1不行的原因。
在这里我们也可以看出:
编译器会将block的内部代码生成对应的函数
SO
我们总结下,block在内部会作为一个指向结构体的指针,当调用block的时候其实就是根据block对应的指针找到相应的函数,进而进行调用,并传入自身
__block的实现
我们再来看看 _block, _block也被转换成了结构体,并含有5个变量
struct __Block_byref_num_0 { void *__isa; // isa指针__Block_byref_num_0 *__forwarding; // 实例本身 int __flags; int __size; int num; // 我们的num值};
图片对应着blockFunc2中的
__block int num = 100;
当创建num并用__block修饰的时候,会初始化这五个变量
当我们执行
num = 200;
对应着
(num.__forwarding->num) = 200;
上面刚刚提到过 _ _forwarding是实例本身,即类型结构体__Block_byref_num_0的&num,再找到对应的num变量,将其原来的100修改为200~~
到此,关于Block内部实现的揭晓也就到此结束了,希望本文能让你对block有更深的理解,感谢你耐心的阅读!
作者:LinXunFeng
链接:http://www.jianshu.com/p/92ea0753ecf4
來源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
- Block的内部实现原理
- Block的实现原理
- block的实现原理
- block的实现原理
- IOS探索之Block的内部实现
- block的实现原理(整理)
- block的用法 实现原理
- block的实现原理(二)
- WaitForSingleObject 的内部实现原理
- SDWebImage的内部实现原理
- KVO内部的实现原理
- EventBus的内部实现原理
- hashMap的内部实现原理
- KVO的内部实现原理
- weak 的内部实现原理
- block内部的引用
- Objective-C的Block的实现原理
- Block的使用与实现原理
- spring boot cache理论详解
- 事件委托
- C#连接sql server数据库
- DNS | Array | Object | Map | Set | iterable ---[廖雪峰老师js教程笔记]
- 637. Average of Levels in Binary Tree
- Block的内部实现原理
- java的持久化技术选型
- win7 批处理文件默认以管理员身份运行及清除IE缓存脚本
- Unity制作游戏中技能使用后转CD的场景
- 将一个本地项目提交到git
- 数据结构 — 希尔排序
- c#一些概念
- svn的cleanup失败的解决方案
- 迷宫找最短路径 深度优先—C