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- ...
随机推荐
- DNW烧写FL2440 NAND Flash分区
转自 calvinlee1984 Subject:DNW烧写FL2440 NAND Flash分区 Date: 2-Mar-2011 By: Calvinlee1984@163 ...
- [Nuxt] Add Arrays of Data to the Vuex Store and Display Them in Vue.js Templates
You add array of todos to the store simply by adding them to the state defined in your store/index.j ...
- [Angular] Implementing A General Communication Mechanism For Directive Interaction
We have modal implement and now we want to implement close functionality. Becuase we use a structure ...
- Linux动态链接库的创建与使用
Linux动态链接库的创建与使用1. 介绍 使用GNU的工具我们如何在Linux下创建自己的程序函数库?一个“程序函数库”简单的说就是一个文件包含了一些编译好的代码和数据,这些编译好的代码和数 ...
- layer iframe 之间传值和关闭iframe弹窗
1.访问父页面元素值 var parentId=parent.$("#id").val();//访问父页面元素值 2.访问父页面方法 var parentMethodValue=p ...
- 我的前端规范——JavaScript篇
相关文章 简书原文:https://www.jianshu.com/p/5918c283cdc3 我的前端规范——开篇:http://www.cnblogs.com/shcrk/p/9271561.h ...
- (十)RabbitMQ消息队列-高可用集群部署实战
原文:(十)RabbitMQ消息队列-高可用集群部署实战 前几章讲到RabbitMQ单主机模式的搭建和使用,我们在实际生产环境中出于对性能还有可用性的考虑会采用集群的模式来部署RabbitMQ. Ra ...
- Android官方数据绑定框架DataBinding(一)
还记得在博客<高逼格UI-ASD(Android Support Design)>的開始曾经说过,Android最新推出了一个官方的数据绑定框架-Data Binding Library. ...
- js进阶正则表达式实现过滤字符串(RegExp对象操作正则表达式)(正则:regular)(表达式:expression)
js进阶正则表达式实现过滤字符串(RegExp对象操作正则表达式)(正则:regular)(表达式:expression) 一.总结 1.str_replace:正则作用:高效快速匹配 2.break ...
- GCD网络多线程---同步运行,异步运行,串行队列,并行队列
总结:同步(无论是串行还是并行)----不又一次开辟子线程 异步(无论是串行还是并行)----开辟子线程 GCD: dispatch queue 主线程的main queue 并行队列 global ...