iOS OC语言: Block底层实现原理

来源http://www.wtoutiao.com/p/11dgbk4.html

先来简单介绍一下Block

Block是什么?

苹果推荐的类型,效率高,在运行中保存代码。用来封装和保存代码,有点像函数,Block可以在任何时候执行。

Block和函数的相似性:(1)可以保存代码(2)有返回值(3)有形参(4)调用方式一样。

Block 底层实现

定义一个简单的block

我们再给a赋值为20,此时打印出来a 的值还是10

但当我们在第一次给a 赋值时,前面加上__block 的时候,则打印出来20。

那么为什么加上__block 后 就打印出20了呢,这个原理是什么呢?

其实可以用两个词来概括:传值 和传址。 可能这样说大家觉得有点扯,接下来 用C++ 代码进行编译。

打开终端做如下操作 在当前文件夹下会得到一个.cpp 文件。

此时打开当前的.cpp 文件(会有差不多10万行代码),前面我们都忽略,只需要滚动到最后,此时你会发现block跟OC中的变化。

接下来我们一个个来看这个block,先来看等号左边的。

 void(*block)()

这是一个没有参数没有返回值的函数指针,既然是一个函数指针,那它就是一个变量,变量里面只能保存函数地址,然后它又在等号的左边是不是意味着右边返回的是一个函数地址(自己推断)。

再看等号右边:

((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, a));
  • 参数(自我推断):

((void (*)()) 强转(自己理解其实没有实际含义,不影响自己本身的类型)

& 取址 后面都是函数的调用,如果不是也不会得到一个函数指针的。

__main_block_impl_0 这是一个函数名,这个函数有三个参数, com+F 搜索一下,又会发现这是一个结构体,结构体如下:

      struct __main_block_impl_0 {struct __block_impl impl;struct __main_block_desc_0* Desc;int a;

可能你会疑惑,刚刚说这是一个函数,而现在是一个结构体。其实在 c++ 里面结构体相当于OC的类,c++ 里面结构体拥有自己的属性以及构造方法和方法。那么为什么取一个结构体的地址呢? 其实它取得是下面这段代码的地址:

    __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int _a, int flags=0) : a(_a) {impl.isa = &_NSConcreteStackBlock;impl.Flags = flags;impl.FuncPtr = fp;Desc = desc;}

那么在上面个方法实现里,又有四个参数。而在刚刚调用的时候只有三个参数,多了一个参数 flags= 0,这个参数其实就相当于Swift中指定了一个默认值,不传也有值,可以忽略。那么后面继续:

a(_a) : 在 c++ 里面 指定_a(形参) 将来赋值给a 这个实参,也就是这个__main_block_impl_0 结构体中的 int a;在这里 int a = 10;

impl.FuncPtr = fp; 将fp赋值给了 impl 结构体的 FuncPtr 参数, 在这个参数里面存放的是下面这段代码的地址:

    static void __main_block_func_0(struct __main_block_impl_0 *__cself) {int a = __cself->a; // 这里 int a = 10;printf("%d\\\\\\\\n",a); // 打印出a}__main_block_desc_0_DATA com+ F 搜索 定义的就是与大小相关的信息,代码如下: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)};

a 直接放a 其实就相当于把a 当前的值拿过来,如果是&a, 就是a的地址。请看下图:

接下来,又重新给 a赋值为 20,但是Block 最终要找到 FuncPtr 里面存放的是值来执行, 在这里才会最终执行打印a 的值的代码,但是这段代码里 a 是 10 了。所以最终打印的还是10。

最后可以概括为block 底层实现 分两种:刚刚上面的就是第一种(不加__block), 会创建一个结构体,实现构造方法,来接收三个参数。

接下来看加上__block 的实现。

修改我们的代码:

再次在终端里面进行编译,你会发现生成的结构体会变化。

等号左边会封装一个__Block_byref_a_0 结构体类型的变量a,下面是结构体的声明:

  truct __Block_byref_a_0 {void *__isa;   //isa 类型的指针 自己的类型__Block_byref_a_0 *__forwarding;  //与自己结构体同名,是一个自己类型的结构体的指针,存放的是自己的地址int __flags;  // 标记int __size;  // 类型的大小int a;  // a 属性 保存变量的值};

等号右边:

  {(void*)0,(__Block_byref_a_0 *)&a, 0, sizeof(__Block_byref_a_0), 10};
  • 参数:

      (void*)0 : 一个指针直接存到isa里面(__Block_byref_a_0 *)&a: 强转 存放的是自己的地址0 : 会传给 flagssizeof(__Block_byref_a_0), 10: 类型的大小10: a 的值, 仅仅是创建。

这 里仅仅是创建,因为使用了__block 所以创建了一个block 类型的结构体,接下来会才是调用block,你会发现其余参数和第一种实现都一样,唯一不同的是再去取值的时候,拿到的是结构体的地址,只要把地址传递过 去,就有了最高的操作权限,到时候再去取值就可以取到内存中最新的值。

接下来(a.__forwarding->a) = 20; 这句代码是拿到结构体里面的地址去修改a的值为20。

后面再去打印,打印的就是内存地址中最新的值,所以就是20。

作者:Liwjing
地址:http://www.jianshu.com/users/8df89a9d8380/latest_articles

转载于:https://www.cnblogs.com/sundaysgarden/p/5602456.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/430443.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

计算机过程控制系统教材,过程控制系统-样章试读.PDF

过程控制系统-样章试读.PDF高等院校教材过程控制系统陈夕松  汪木兰  主编李  奇      主审KB2北  京内 容 简 介本书以过程控制系统组成和结构为线索,介绍了过程控制的基本概念,过程控制常用仪表的原理和工程选用,过程对象及建模方法…

sufeinet

http://www.sufeinet.com http://tool.sufeinet.com/ 转载于:https://www.cnblogs.com/shiningrise/p/5603557.html

计算机如何取消还原卡,如何关闭硬件还原卡?

2009-11-06有什么方法可以让电脑每次关机都可以自动删1)打开控制面板/性能维护/管理工具/双击本地安全策略,在右侧选“关机清理虚拟内存页面文件”双击他选“已启用”按应用重启即可。2)建议下载超级兔子是免费的小巧著名的软件,选择清理系统垃圾(全选)&…

服务器虚拟主机推荐,免费的虚拟主机推荐

写在前面:免费虚拟主机免费虚拟主机是指IDC服务商“免费”为站长提供网页寄存服务。免费虚拟主机--用于制作免费个人网站,是学习网页设计的好方法。虚拟主机就是指网站空间,是在网络服务器上划分出一定的磁盘空间供用户放置站点、应用组件等&…

如何优化虚拟桌面

虚拟桌面代理安装的具体优化: 禁止Windows 自动更新[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update]"AUOptions"dword:00000001"ScheduledInstallDay"dword:00000000"ScheduledInstallTime&qu…

服务器配置和性能,服务器性能配置(硬件)

原标题:服务器性能配置(硬件)1.CPU大部分的CPU在同一时间内只能运行一个线程,但是超线程的处理器可以在同一个时间运行多个线程,可以利用处理前超线程特性提高系统性能。虽然采用超线程技术能同时执行两个线程,但它并不象两个真正…

js/css文件修改后浏览器本地缓存解决

本文实例讲述了让html页面随js的修改来更新缓存的实现方法。分享给大家供大家参考。具体实现方法如下: 很多朋友都会碰到这样的情况:如果我们页面加载了js的话下次打开时也会是调用这个js缓存文件,但对于我们修改后调试和发布是非常的不方便了…

图片自动翻转css代码,用css实现图片翻转(示例代码)

简介这篇文章主要介绍了用css实现图片翻转(示例代码)以及相关的经验技巧,文章约1193字,浏览量447,点赞数1,值得参考!用css实现图片翻转.flip-container {perspective:1000px;}.flip-container:hover .flipper {transfo…

06:月度开销

题目链接:http://noi.openjudge.cn/ch0111/06/ 总时间限制: 1000ms 内存限制: 65536kB描述  农夫约翰是一个精明的会计师。他意识到自己可能没有足够的钱来维持农场的运转了。他计算出并记录下了接下来 N (1 ≤ N ≤ 100,000) 天里每天需要的开销。 约翰打算为连续…

ajax传值controller怎么写,ajax如何传递参数给controller

前台:‘type‘ : ‘post‘,‘contentType‘ : ‘application/json;charsetUTF-8‘,‘data‘ : JSON.stringify(JsonObject),其中JsonObject就是你组装的JSON对象后台:RequestMapping(value "/query", method RequestMethod.PO…

mc服务器玩家无限掉线怎么办,服务器频繁掉线 求解

该楼层疑似违规已被系统折叠 隐藏此楼查看此楼Mods loaded: 37ModLoader 1.1mod_MinecraftForge 1.3.3.12mod_ModLoaderMp 1.1mod_NotEnoughItems 1.1.2mod_ReiMinimap v3.0_01 [1.1]mod_AnimalBikes AnimalBikes 1.9.0mod_BuildCraftCore 2.2.12mod_BuildCraftBuilders 2.2.12…

delphi中的copy,delete,pos和leftstr,RightStr的用法

copy举个例子:str : “123456”;str1 : Copy(Str,2,3);结果就是 str1 等于 234。Copy有3个参数,第一个是你要处理的字符串,第二个是你要截取的开始位置,第3个是截取位数。当你的第3个参数大于字符长度,那么效果就是取 …

js中报错 ajax不存在,AJAX

AJAX : Asynchronous JavaScript and XML 异步JavaScript和XML (XML更多的是被JSON格式替代使用)AJAX 只做一件事情:异步获取数据,更为重要的是还是JS对返回的数据进行操作。异步获取数据极大地改善web与用户的数据交互(如下图左侧为传统web,右侧为借…

nylon尼龙的来历

nylon 尼龙 在1938年,美国杜邦(du pont)公司用工业原料试制出的一种合成纤维,老板让职员们取一个好记又适用于各种语言的名字,结果就取成了这个nylon。先是作为商标,后来作为产品属名。 乙烯vinyl和人造丝r…

iOS开发内购图文教程

2015年最全的内购图文教程,首先是填各种资料,最后是代码,废话不多说,直接上图 第一部分协议 第一步.png第二步.jpg第三步.jpg第四步.png第五步.png第六步.png第七步.jpg第八步.jpg第九步.jpg第十步.pngCNAPS CODE 查询地址https:/…

cisco服务器维修,面向终端的AMP控制台的思科维护的排除列表更改

简介本文档介绍添加到思科维护的例外项的更改。思科维护的例外项由思科创建和维护,以便在面向终端的高级恶意软件防护(AMP)连接器和防病毒、安全或其他软件之间提供更好的兼容性,这些例外项可以添加到应用的新版本。作者:思科工程师Caly Hess…

服务器怎么用光驱装系统教程,使用光驱重装系统详细教程

电脑系统在用了很长一段时间后总会出现卡顿或者其他的问题,这时很多小伙伴后就会选择进行系统的重装,系统的重装也是有多种方法的,比如使用U盘进行重装,或者使用光驱,而今天小编要给大家分享的就是使用光驱重装系统的详…

struts2 Eclipse 中集成strust2开发框架实例

下面通过建立一个小的实例具体来说明Eclipse 集成struts2,以下实例采用的为 struts2 版本为 struts2 2.2.3.1 为应用. 1. 下载struts2的开发包 第一步: 在浏览器中输入 http://apache.org 第二步:在apche的页面项目中选择struct 点击连接进入相关页面 第三步: 点击download选择…

电脑电池,笔记本电池校正,教您怎样校正笔记本电脑电池

只要留个心,就会发现身边的很多人都在使用着笔记本电脑,不过笔记本电脑使用久了,电池可能会出现虚电的情况,导致我们的笔记本的续航时间变短了,这时候需要我们手动对笔记本电池进行校准,为此,小…

手机网站——自适应

最近自己做的手机网管的页面,在手机上显示的时候,总是要手动进行页面缩放,这样子一来.采用Opera和 safari 等手机浏览器的时候,页面变形得很厉害,第一次用领导到的Iphone的时候.页面字变得太小,要缩放才可以.参考了3g.163 Yahoo ,Live 的页面后,发现CSS并无太大的区别.所以不是…