Objective-C block实现代码分析
block内部结构
让我们写一个block
void exampleBlock() {
// NSConcreteStackBlock
int a = 1;
__block int b = 2;
int(^blockTest0)(int c) = ^(int c){
return a + b + c;
};
int c = 3;
blockTest0(c); // NSConcreteGlobalBlock
void(^blockTest2)(void) = ^(void){
;
};
blockTest2();
}
用clang转成c分析下
clang -rewrite-objc block.c
能够看到他们的定义是
struct __exampleBlock_block_impl_0 {
struct __block_impl impl;
struct __exampleBlock_block_desc_0* Desc;
int a;
__Block_byref_b_0 *b; // by ref
__exampleBlock_block_impl_0(void *fp, struct __exampleBlock_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;
}
}; // __block_impl
struct __block_impl {
void *isa;
int Flags;
int Reserved;
void *FuncPtr;
}; // __exampleBlock_block_desc_0
struct __exampleBlock_block_impl_0 {
struct __block_impl impl;
struct __exampleBlock_block_desc_0* Desc;
int a;
__Block_byref_b_0 *b; // by ref
__exampleBlock_block_impl_0(void *fp, struct __exampleBlock_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;
}
}; // __exampleBlock_block_impl_2
struct __exampleBlock_block_impl_2 {
struct __block_impl impl;
struct __exampleBlock_block_desc_2* Desc;
__exampleBlock_block_impl_2(void *fp, struct __exampleBlock_block_desc_2 *desc, int flags=0) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
初始化和运行代码
void exampleBlock() {
// blockTest0
int a = 1;
__attribute__((__blocks__(byref))) __Block_byref_b_0 b = {(void*)0,(__Block_byref_b_0 *)&b, 0, sizeof(__Block_byref_b_0), 2}; int(*blockTest0)(int c) = (int (*)(int))&__exampleBlock_block_impl_0((void *)__exampleBlock_block_func_0, &__exampleBlock_block_desc_0_DATA, a, (__Block_byref_b_0 *)&b, 570425344); int c = 3;
((int (*)(__block_impl *, int))((__block_impl *)blockTest0)->FuncPtr)((__block_impl *)blockTest0, c); // blockTest2
void(*blockTest2)(void) = (void (*)())&__exampleBlock_block_impl_2((void *)__exampleBlock_block_func_2, &__exampleBlock_block_desc_2_DATA);
((void (*)(__block_impl *))((__block_impl *)blockTest2)->FuncPtr)((__block_impl *)blockTest2);
}
我们先看看blockTest2,它是由 结构体impl, 结构体Desc, 构造方法__exampleBlock_block_impl_2() 组成展开后是
- *isa 指向该实例对象(代码里是NSConcreteStackBlock,事实上应该是NSConcreteGlobalBlock)
- Flags 用于按bit位表示一些block的附加信息
- reserved 保留变量
- *FuncPtr 函数指针,指向详细的block实现的函数调用地址(代码里是__exampleBlock_block_func_2)
static void __exampleBlock_block_func_2(struct __exampleBlock_block_impl_2 *__cself) {
;
}
- size_t reserved 这个传进来的是0
- Block_size 结构体的大小
static struct __exampleBlock_block_desc_2 {
size_t reserved;
size_t Block_size;
} __exampleBlock_block_desc_2_DATA = { 0, sizeof(struct __exampleBlock_block_impl_2)};
然后我们在看blockTest,它比blockTest2多了2个变量a, b
int a; 外部变量a,
Block_byref_b_0 *b; 加了block修饰的b, 传的是 Block_byref_b_0
在生成的初始化代码中则多了3个传入值
int(*blockTest0)(int c) = (int (*)(int))&__exampleBlock_block_impl_0((void *)__exampleBlock_block_func_0, &__exampleBlock_block_desc_0_DATA, a, (__Block_byref_b_0 *)&b, 570425344);
a是这个是直接传值进去,然后被复制给 a
b是传的地址, 是把 __Block_byref_b_0 赋值给 b
__Block_byref_b_0这个结构体是
struct __Block_byref_b_0 {
void *__isa;
__Block_byref_b_0 *__forwarding;
int __flags;
int __size;
int b;
};
__forwarding 是一个指向自己的指针.
__Block_byref_b_0 的初始化代码例如以下:
__attribute__((__blocks__(byref))) __Block_byref_b_0 b = {(void*)0,(__Block_byref_b_0 *)&b, 0, sizeof(__Block_byref_b_0), 2};
我们能够看出a是直接复制进去的,b是被转到了一个结构体里,然后吧这个结构体的指针传进去,所以block不能改动a,能改动b.
- 570425344 这个应该是传给Flags
blockTest0的Desc和blockTest2也有所不同,展开后是
static struct __exampleBlock_block_desc_0 {
size_t reserved;
size_t Block_size;
void (*copy)(struct __exampleBlock_block_impl_0*, struct __exampleBlock_block_impl_0*);
void (*dispose)(struct __exampleBlock_block_impl_0*);
} __exampleBlock_block_desc_0_DATA = { 0, sizeof(struct __exampleBlock_block_impl_0), __exampleBlock_block_copy_0, __exampleBlock_block_dispose_0};
多了2个函数指针copy, dispose,对于在调用前后改动对应变量的引用计数, 分别指向
static void __exampleBlock_block_copy_0(struct __exampleBlock_block_impl_0*dst, struct __exampleBlock_block_impl_0*src) {_Block_object_assign((void*)&dst->b, (void*)src->b, 8/*BLOCK_FIELD_IS_BYREF*/);} static void __exampleBlock_block_dispose_0(struct __exampleBlock_block_impl_0*src) {_Block_object_dispose((void*)src->b, 8/*BLOCK_FIELD_IS_BYREF*/);}
再来看下blockTest0的*FuncPtr
static int __exampleBlock_block_func_0(struct __exampleBlock_block_impl_0 *__cself, int c) {
__Block_byref_b_0 *b = __cself->b; // bound by ref
int a = __cself->a; // bound by copy return a + (b->__forwarding->b) + c;
}
如可以看到的a使用输入的副本a, b使用一种结构,其中b
版权声明:本文博主原创文章。博客,未经同意不得转载。
Objective-C block实现代码分析的更多相关文章
- STM32启动代码分析 IAR 比较好
stm32启动代码分析 (2012-06-12 09:43:31) 转载▼ 最近开始使用ST的stm32w108芯片(也是一款zigbee芯片).开始看他的启动代码看的晕晕呼呼呼的. 还好在c ...
- [Asp.net 5] DependencyInjection项目代码分析4-微软的实现(4)
这个系列已经写了6篇,链接地址如下: [Asp.net 5] DependencyInjection项目代码分析 [Asp.net 5] DependencyInjection项目代码分析2-Auto ...
- Device Tree(三):代码分析【转】
转自:http://www.wowotech.net/linux_kenrel/dt-code-analysis.html Device Tree(三):代码分析 作者:linuxer 发布于:201 ...
- Linux内核中的GPIO系统之(3):pin controller driver代码分析
一.前言 对于一个嵌入式软件工程师,我们的软件模块经常和硬件打交道,pin control subsystem也不例外,被它驱动的硬件叫做pin controller(一般ARM soc的datash ...
- Device Tree(三):代码分析
一.前言 Device Tree总共有三篇,分别是: 1.为何要引入Device Tree,这个机制是用来解决什么问题的?(请参考引入Device Tree的原因) 2.Device Tree的基础概 ...
- 【转】Device Tree(三):代码分析
原文网址:http://www.wowotech.net/linux_kenrel/dt-code-analysis.html 一.前言 Device Tree总共有三篇,分别是: 1.为何要引入De ...
- 虚拟机创建流程中neutron代码分析(三)
前言: 当neutron-server创建了port信息,将port信息写入数据库中.流程返回到nova服务端,接着nova创建的流程继续走.在计算节点中neutron-agent同样要完成很多的工作 ...
- Linux时间子系统之(十七):ARM generic timer驱动代码分析
专题文档汇总目录 Notes:ARM平台Clock/Timer架构:System counter.Timer以及两者之间关系:Per cpu timer通过CP15访问,System counter通 ...
- Linux kernel的中断子系统之(七):GIC代码分析
返回目录:<ARM-Linux中断系统>. 总结: 原文地址:<linux kernel的中断子系统之(七):GIC代码分析> 参考代码:http://elixir.free- ...
随机推荐
- 利用Eclipse+openJTAG调试led.axf文件
转自calvinlee1984 Subject:利用Eclipse+openJTAG调试led.axf文件 Date: 3-Mar-2011 By: Calvinlee1984 ...
- Android 利用an框架快速实现网络请求(含下载上传文件)
作者:Bgwan链接:https://zhuanlan.zhihu.com/p/22573081来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处. an框架的网络框架是完全 ...
- Docker搭建ES
Centos7安装ES 和 Docker搭建ES 文版权归博客园和作者吴双本人共同所有 转载和爬虫请注明原文地址 www.cnblogs.com/tdws 一.linux centos7.x安装ES ...
- 【u251】心灵的抚慰
Time Limit: 1 second Memory Limit: 128 MB [问题描述] 病毒问题解决后,神牛们的心灵久久不能平静.他可以从一个程序联想到一些相似的程序.比如从程序1联想到2, ...
- 细说document.ready和window.onload
原文 简书原文:https://www.jianshu.com/p/bbf28d61aa1f 大纲 1.对页面加载的认识 2.关于document.ready() 3.关于document.onloa ...
- hdu 2577 How to Type(DP)
How to Type Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Tota ...
- php$get中文汉字参数乱码
最近写了个简单的页面,从浏览器中传入中文参数(test.php?name=测试),不论怎么设置utf-8的页面中都显示乱码,google了一把也查到了不少解决办法,但是问题的原因到底是什么呢?没有人深 ...
- Swift基础1.1——基本的语法—变量和常量
前些日子.第一届Swift开发人员大会开了之后.身边非常多搞OC的朋友就按捺不住了. 都认为是时候学一下Swift了,毕竟Swift已是趋势. 也是应他们再三要求,让我整理一下Swift的学习心得.今 ...
- VC++ 訪问数据库实例具体解释图解
一 ADO 方式訪问 Access 新建一个对话框project,加入控件,如图: watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2 ...
- jquery-2 jQuery原理和核心方法(多看学习视频)
jquery-2 jQuery原理和核心方法(多看学习视频) 一.总结 一句话总结:jQuery就是普通的js对象,只不过方法比较多而已,属性就length一个. 1.jquery的链式操作的底层原 ...