iOS 技术篇:从使用到了解block底层原理 (二)
block实质
序言
上篇文章中主要通过简单的demo展示了block的使用场景,本篇将基于上篇文章iOS 技术篇:从使用到了解block底层原理 (一)进一步了解block底层的实现原理。
block作为一种"带有自动变量值的匿名函数",在实际编译时,我们无法转换成我们能够理解的源代码,但clang(LLVM编译器)具有转化为我们可读源代码的功能。终端输入如下命令行,可获取.cpp文件。
clang -rewrite-objc 源代码文件名
在main.m中实现如下
int main(int argc, const char * argv[]) {
@autoreleasepool {
void(^myBlock)(void)=^{
NSLog(@"testtest");
};
myBlock();
}
return 0;
}
通过clang我们获取到main.cpp 文件,打开文件我们可以看到大约10w行代码,当然我们不用从头到尾细细分析每块的功能。我们只需要看最后几行然后步步分析就可以。
int main(int argc, const char * argv[]) {
/* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool;
void(*myBlock)(void)=((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA));
((void (*)(__block_impl *))((__block_impl *)myBlock)->FuncPtr)((__block_impl *)myBlock);
}
return 0;
}
在main函数入口这里我们可以看到我们原实现block被转化为了另一种方式展示。不要着急看不到,从这里开始一步步分析。
void(*myBlock)(void)=((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA));
通过全局搜索可以看到__main_block_impl_0的内部结构是:
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;
}
};
这里包含了两个结构体block_impl和main_block_desc_0,
struct __block_impl {
void *isa;
int Flags;
int Reserved;
void *FuncPtr;
};
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)};
//__main_block_impl_0 结构声明
__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;
}
不难看出: 1.main_block_impl_0就是block的一个C++的实现,_0代表是main中的第几个block,里面包含了保留值reserved和大小Block_size。 2.block_impl 就是block的内部实现。其中包含了 isa指针、flags标示、reserved保留值和funcPtr定义类型 (ps:_NSConcreteStackBlock相当于class_t结构体实例 想知道可以自己了解下)。
从这里我们可以大概看出main_block_impl_0就是传了两个值main_block_func_0和&main_block_desc_0_DATA。一个是func结构体,另一个是desc指针。 以上就是初始化main_block_impl_0结构体成员的源代码。 接下来,将我们原来看到不太容易理解的__main_block_impl_0通过以上分析可以将
void(*myBlock)(void)=((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA));
转化为:
struct __main_block_impl_0 tmp = __main_block_impl_0(__main_block_func_0, &__main_block_desc_0_DATA);
struct __main_block_impl_0*myBlock = &tmp;
这样就容易理解了,该源代码将main_block_impl_0 结构体类型的自动变量,即栈上生成的main_block_impl_0结构体实例的指针,赋值给__main_block_impl_0结构体指针类型的变量myBlock。 而myBlock();的底层实现如下:
((void (*)(__block_impl *))((__block_impl *)myBlock)->FuncPtr)((__block_impl *)myBlock);
转化之后就是
(*myBlock->impl.FuncPtr)(myBlock);
这就是简单的函数指针调用函数。
可以理解为:有block语法转化的__main_block_func_0函数的指针被赋值成员变量FuncPtr中。
到此也就了解了block的实质。
iOS 技术篇:从使用到了解block底层原理 (二)的更多相关文章
- iOS 技术篇:从使用到了解block底层原理 (一)
1.概述 block : Object - C对于闭包的实现 . 闭包 = 一个函数(或是指向函数的指针) +该函数执行的外部的上下文变量(自由变量) 2.对block的理解 可以嵌套定义,定义 bl ...
- [置顶] Asp.Net底层原理(二、写自己的Asp.Net框架)
我们介绍过了浏览器和服务器之间的交互过程,接下来介绍Asp.net处理动态请求. 写自己的Asp.Net框架,我们不会引用System.Web这个程序集,我们只需要创建要给自己的类库,所以在接下来的程 ...
- 《React Native 精解与实战》书籍连载「React Native 底层原理」
此文是我的出版书籍<React Native 精解与实战>连载分享,此书由机械工业出版社出版,书中详解了 React Native 框架底层原理.React Native 组件布局.组件与 ...
- iOS - Block底层解析
Block是iOS开发中一种比较特殊的数据结构,它可以保存一段代码,在合适的地方再调用,具有语法简介.回调方便.编程思路清晰.执行效率高等优点,受到众多猿猿的喜爱.但是Block在使用过程中,如果对B ...
- iOS底层原理总结 - 探寻block的本质(一)
面试题 block的原理是怎样的?本质是什么? __block的作用是什么?有什么使用注意点? block的属性修饰词为什么是copy?使用block有哪些使用注意? block在修改NSMu ...
- iOS OC语言: Block底层实现原理
先来简单介绍一下BlockBlock是什么?苹果推荐的类型,效率高,在运行中保存代码.用来封装和保存代码,有点像函数,Block可以在任何时候执行. Block和函数的相似性:(1)可以保存代码(2) ...
- iOS OC语言: Block底层实现原理 (转载)
作者:Liwjing 地址:http://www.jianshu.com/users/8df89a9d8380/latest_articles 先来简单介绍一下Block Block是什么? 苹果推荐 ...
- iOS Block的本质(二)
iOS Block的本质(二) 1. 介绍引入block本质 通过上一篇文章Block的本质(一)已经基本对block的底层结构有了基本的认识,block的底层就是__main_block_impl_ ...
- Objective-C中block的底层原理
先出2个考题: 1. 上面打印的是几,captureNum2 出去作用域后是否被销毁?为什么? 同样类型的题目: 问:打印的数字为多少? 有人会回答:mutArray是captureObject方法的 ...
随机推荐
- ElasticSearch 表结构信息 提取
参考: es-sql: https://github.com/NLPchina/elasticsearch-sql/releases 执行SQL语句SearchDao org.nlpcn.es4sql ...
- PAT乙级完结有感
去年10月开始刷的题,拖拖拉拉的终于借这个假期刷完了,总的来说还是有点小激动的,毕竟,第一次刷完一个体系,在这之前,我在杭电.南阳.洛谷.leetcode.以及我们自己学校的OJ上刷过,但都没有完完整 ...
- PAT B1019/A1069 数字黑洞
给定任一个各位数字不完全相同的四位正整数,如果先把四个数字按照非递增排序,再按照非递减排序,然后用第一个数字减第二个数字,将得到一个新的数字,一直重复这样做,很快就会停在有“数字黑洞”之称的6147, ...
- 在github上保存vscode的配置(后续重新安装vscode时,可以十分方便地从github上下载安装这个保存的配置)
1 安装拓展 Settings Sync 在 VSCode 拓展中搜索 Settings Sync 并安装,安装完成后,重启 2 设置 Github Person Access Token 进入这个页 ...
- (转)Dom4j中的中文编码问题
一.“中文问题没商量”之Dom4j中的编码问题 本文主要讲述的是Dom4j在把Document保存到文件过程中出现的一个中文问题,本文跟<80前>一文一样,以Spring项目无关,请“春 ...
- ROS-5 : 自定义消息
自定义消息一般存储在功能包的msg文件夹下的.msg文件中,这些定义可告诉ROS这些数据的类型和名称,以便于在ROS 节点中使用.添加完这些自定义消息后,ROS会将其转为等效的C++节点,从而可在其他 ...
- CF755G PolandBall and Many Other Balls 题解
从神 Karry 的题单过来的,然后自己瞎 yy 了一个方法,看题解区里没有,便来写一个题解 一个常数和复杂度都很大的题解 令 \(dp_{i,j}\) 为 在 \(i\) 个球中选 \(j\) 组的 ...
- MongoDB安装+基础操作
MongoDB 一. 安装 这里展示使用docker安装mongoDB 拉取最新MongoDB镜像 docker pull mongo 运行容器 docker run -itd --name mong ...
- ModelSim安装步骤
刚成功安装了软件的我反手就是一篇安装步骤分享. 这是我自己创建的永久百度云链接. ModelSim10.7软件下载百度云链接 网址:https://pan.baidu.com/s/14oGZytocA ...
- Windows 10长脸了!
Windows 10一直毁誉参半,但是在微软的持续升级完善之下,同时随着时间的流逝,已经顺利成为全球第一大桌面操作系统,并开始逐渐甩开Windows 7,全球设备安装量已经达到约8亿部. 根据最新的S ...