谈Objective-C Block的实现(转载唐巧)
唐巧的技术博客
谈Objective-C Block的实现
JUL 28TH, 2013
前言
这里有关于block的5道测试题,建议你阅读本文之前先做一下测试。
先介绍一下什么是闭包。在wikipedia上,闭包的定义)是:
In programming languages, a closure is a function or reference to a function together with a referencing environment—a table storing a reference to each of the non-local variables (also called free variables or upvalues) of that function.
翻译过来,闭包是一个函数(或指向函数的指针),再加上该函数执行的外部的上下文变量(有时候也称作自由变量)。
block实际上就是Objective-C语言对于闭包的实现。 block配合上dispatch_queue,可以方便地实现简单的多线程编程和异步编程,关于这个,我之前写过一篇文章介绍:《使用GCD》。
本文主要介绍Objective-C语言的block在编译器中的实现方式。主要包括:
- block的内部实现数据结构介绍
- block的三种类型及其相关的内存管理方式
- block如何通过capture变量来达到访问函数外的变量
实现方式
数据结构定义
block的数据结构定义如下(图片来自这里):
对应的结构体定义如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
通过该图,我们可以知道,一个block实例实际上由6部分构成:
- isa指针,所有对象都有该指针,用于实现对象相关的功能。
- flags,用于按bit位表示一些block的附加信息,本文后面介绍block copy的实现代码可以看到对该变量的使用。
- reserved,保留变量。
- invoke,函数指针,指向具体的block实现的函数调用地址。
- descriptor, 表示该block的附加描述信息,主要是size大小,以及copy和dispose函数的指针。
- variables,capture过来的变量,block能够访问它外部的局部变量,就是因为将这些变量(或变量的地址)复制到了结构体中。
该数据结构和后面的clang分析出来的结构实际是一样的,不过仅是结构体的嵌套方式不一样。但这一点我一开始没有想明白,所以也给大家解释一下,如下2个结构体SampleA和SampleB在内存上是完全一样的,原因是结构体本身并不带有任何额外的附加信息。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
在Objective-C语言中,一共有3种类型的block:
- _NSConcreteGlobalBlock 全局的静态block,不会访问任何外部变量(block里面没有局部变量的时候)。
- _NSConcreteStackBlock 保存在栈中的block,当函数返回时会被销毁。
- _NSConcreteMallocBlock 保存在堆中的block,当引用计数为0时会被销毁。
我们在下面会分别来查看它们各自的实现方式上的差别。
研究工具:clang
为了研究编译器是如何实现block的,我们需要使用clang。clang提供一个命令,可以将Objetive-C的源码改写成c语言的,借此可以研究block具体的源码实现方式。该命令是
1 |
|
NSConcreteGlobalBlock 类型的block的实现
我们先新建一个名为block1.c的源文件:
1 2 3 4 5 6 7 |
|
然后在命令行中输入clang -rewrite-objc block1.c
即可在目录中看到clang输出了一个名为block1.cpp的文件。该文件就是block在c语言实现,我将block1.cpp中一些无关的代码去掉,将关键代码引用如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
|
下面我们就具体看一下是如何实现的。__main_block_impl_0就是该block的实现,从中我们可以看出:
- 一个block实际是一个对象,它主要由一个 isa 和 一个 impl 和 一个descriptor组成。
在本例中,isa指向 _NSConcreteGlobalBlock, 主要是为了实现对象的所有特性,在此我们就不展开讨论了。- 由于clang改写的具体实现方式和LLVM不太一样,并且这里没有开启ARC。所以这里我们看到isa指向的还是
_NSConcreteStackBlock
。但在LLVM的实现中,开启ARC时,block应该是_NSConcreteGlobalBlock类型,具体可以看《objective-c-blocks-quiz》第二题的解释。 - impl是实际的函数指针,本例中,它指向__main_block_func_0。这里的impl相当于之前提到的invoke变量,只是clang编译器对变量的命名不一样而已。
- descriptor是用于描述当前这个block的附加信息的,包括结构体的大小,需要capture和dispose的变量列表等。结构体大小需要保存是因为,每个block因为会capture一些变量,这些变量会加到__main_block_impl_0这个结构体中,使其体积变大。在该例子中我们还看不到相关capture的代码,后面将会看到。
NSConcreteStackBlock 类型的block的实现
我们另外新建一个名为block2.c的文件,输入以下内容:
1 2 3 4 5 6 7 8 9 10 11 |
|
用之前提到的clang工具,转换后的关键代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
|
在本例中,我们可以看到:
- 本例中,isa指向_NSConcreteStackBlock,说明这是一个分配在栈上的实例。
- main_block_impl_0 中增加了一个变量a,在block中引用的变量a实际是在申明block时,被复制到main_block_impl_0结构体中的那个变量a。因为这样,我们就能理解,在block内部修改变量a的内容,不会影响外部的实际变量a。
- main_block_impl_0 中由于增加了一个变量a,所以结构体的大小变大了,该结构体大小被写在了main_block_desc_0中。
我们修改上面的源码,在变量前面增加__block关键字:
1 2 3 4 5 6 7 8 9 10 11 12 |
|
生成的关键代码如下,可以看到,差异相当大:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
|
转载于:https://www.cnblogs.com/HypeCheng/p/4597205.html
谈Objective-C Block的实现(转载唐巧)相关推荐
- 浅谈OC中Block的本质
Block简介 block是将函数及其执行上下文封装起来的一个对象 在block实现的内部,有很多变量,因为block也是一个对象 其中包含了诸如isa指针,imp指针等对象变量,还有储存其截获变量的 ...
- 唐巧的《iOS开发进阶》 - 读后感
2019独角兽企业重金招聘Python工程师标准>>> 唐巧的<iOS开发进阶> - 读后感 为什么要看书 为什么要多看书呢? 在技术类书籍上,看书的目的,不是为了记住所 ...
- 唐巧的iOS技术博客选摘
1. 那些被遗漏的objective-c保留字:http://blog.devtang.com/blog/2013/04/29/the-missing-objc-keywords/ 2. 使用cras ...
- 技术文摘13 郑钧 泰岳 技术 资料 源码 UI tinypng 保质压缩 github 大神 高仿 VVDocumenter-Xcode 工具 唐巧...
ios 高仿暴风视频播放器app源码 51 高仿城觅by-objective-c 高仿小日子 - By Swift 2.0 有态度的iOS第三方资源聚合网站 iOS122 伽蓝之堂-- 一只魔法师的 ...
- 《iOS 开发进阶(唐巧)》读书笔记
1. CocoaPods 的安装和使用 CocoaPods 是开发 iOS 应用程序的一个第三方库的依赖管理工具,起始于2011年8月,用 Ruby 写的. 1.0 CocoaPods 的原理 Coc ...
- 唐巧:技术人如何成为管理者
唐巧:技术人如何成为管理者 前不久趣直播举办了一场技术人成长交流会.邀请了小猿搜题产品技术负责人唐巧来分享.我也有幸参加了此次的交流会 以下是文字版: 我大概自我介绍一下,我叫唐巧,是小猿搜题的产品技 ...
- 唐巧访谈: iOS大V的技术进阶之路
如果你有志于将iOS开发作为职业,或者已经是一位iOS开发者,那么你应该听说过唐巧的名字.唐巧,2012年从网易有道离开参与创业, 目前是猿题库iOS高级研发工程师.难得的是,他本身是一线的iOS开发 ...
- 读唐巧博客2011年总结感想
看了牛人的博客才知道,人与人之间的差距为什么会越来越大,人家每天都在挑战自己,深化自己,每年看了多少本技术书籍和其他书,再想想自己,感觉无言以对呀,骚年,加油吧! 附上唐巧博客2011总结部分内容; ...
- 使用GCD 转自 Posted by 唐巧
什么是GCD Grand Central Dispatch (GCD)是Apple开发的一个多核编程的解决方法.该方法在Mac OS X 10.6雪豹中首次推出,并随后被引入到了iOS4.0中.GCD ...
最新文章
- Java项目:仿小米商城系统(前后端分离+java+vue+Springboot+ssm+mysql+maven+redis)
- 推荐一个 Java 接口快速开发框架
- SecureCRT安装的注意事项
- ABAP和Java里的单例模式攻击
- Java代码实现负载均衡五种算法
- 简单的数据增强代码(C++与opencv)
- 身价百亿的中本聪是如何打造出“创世区块”的?
- python中根据字符串导入模块module
- ehtools:一款WiFi渗透框架
- 330UF16V 10*7.7片式铝电解电容封装
- vue json对象转数组_年薪百万之路--第六十七天 Vue入门
- Redis 与 Mysql 的数据一致性
- android系统裁剪优化
- MySQL 英文格式日期转换
- 软件缺陷的生命周期(二)
- 后端程序员生产力工具合集
- 快速理解 WAL 机制,架构师必备技能!「建议收藏!!」
- Halide(win10vs2019环境搭建)小试牛刀
- 首汽约车安全出行的点“智”之笔
- D. Progressions Covering