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底层原理 (二)的更多相关文章

  1. iOS 技术篇:从使用到了解block底层原理 (一)

    1.概述 block : Object - C对于闭包的实现 . 闭包 = 一个函数(或是指向函数的指针) +该函数执行的外部的上下文变量(自由变量) 2.对block的理解 可以嵌套定义,定义 bl ...

  2. [置顶] Asp.Net底层原理(二、写自己的Asp.Net框架)

    我们介绍过了浏览器和服务器之间的交互过程,接下来介绍Asp.net处理动态请求. 写自己的Asp.Net框架,我们不会引用System.Web这个程序集,我们只需要创建要给自己的类库,所以在接下来的程 ...

  3. 《React Native 精解与实战》书籍连载「React Native 底层原理」

    此文是我的出版书籍<React Native 精解与实战>连载分享,此书由机械工业出版社出版,书中详解了 React Native 框架底层原理.React Native 组件布局.组件与 ...

  4. iOS - Block底层解析

    Block是iOS开发中一种比较特殊的数据结构,它可以保存一段代码,在合适的地方再调用,具有语法简介.回调方便.编程思路清晰.执行效率高等优点,受到众多猿猿的喜爱.但是Block在使用过程中,如果对B ...

  5. iOS底层原理总结 - 探寻block的本质(一)

        面试题 block的原理是怎样的?本质是什么? __block的作用是什么?有什么使用注意点? block的属性修饰词为什么是copy?使用block有哪些使用注意? block在修改NSMu ...

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

    先来简单介绍一下BlockBlock是什么?苹果推荐的类型,效率高,在运行中保存代码.用来封装和保存代码,有点像函数,Block可以在任何时候执行. Block和函数的相似性:(1)可以保存代码(2) ...

  7. iOS OC语言: Block底层实现原理 (转载)

    作者:Liwjing 地址:http://www.jianshu.com/users/8df89a9d8380/latest_articles 先来简单介绍一下Block Block是什么? 苹果推荐 ...

  8. iOS Block的本质(二)

    iOS Block的本质(二) 1. 介绍引入block本质 通过上一篇文章Block的本质(一)已经基本对block的底层结构有了基本的认识,block的底层就是__main_block_impl_ ...

  9. Objective-C中block的底层原理

    先出2个考题: 1. 上面打印的是几,captureNum2 出去作用域后是否被销毁?为什么? 同样类型的题目: 问:打印的数字为多少? 有人会回答:mutArray是captureObject方法的 ...

随机推荐

  1. 用java实现输出英文小说飘中出现次数最多的前N个单词(附:使用文件读写)

    本文参考于:https://blog.csdn.net/u014204432/article/details/40348839 一.题目 输出单个文件(<飘> 英文版)中的前 N 个最常出 ...

  2. ROS学习笔记9-创建ros消息和服务

    该节内容主要来自于官方文档的两个小节:1.使用rosed来编辑2.创建ros消息的服务 先来看rosed: rosedrosed命令是rosbash的一部分,使用rosed可以直接编辑包中的一个文件, ...

  3. 五、生产者消费者模型_ThreadLocal

    1.生产者消费者模型作用和示例如下:1)通过平衡生产者的生产能力和消费者的消费能力来提升整个系统的运行效率 ,这是生产者消费者模型最重要的作用2)解耦,这是生产者消费者模型附带的作用,解耦意味着生产者 ...

  4. 使用自己定义的DIV的滚动条

    基本思路: 让DIV浮动起来,利用postion:fixed/absolute,设定height:100% var $card=$("#cardDetail");      $ca ...

  5. OKR-Periods of Words「POI 2006」

    题目描述 串是有限个小写字符的序列,特别的,一个空序列也可以是一个串.一个串 P 是串 A 的前缀,当且仅当存在串 B,使得 A = PB.如果 P != A 并且 P 不是一个空串,那么我们说 P  ...

  6. 获取网卡MAC、硬盘序列号、CPU_ID、BIOS编号

    抄来的 获取网卡MAC.硬盘序列号.CPU ID.BIOS编号 本文中所有原理及思想均取自网络,有修改.其中获取硬盘序列号.获取CPU编号.获取BIOS编号的原始代码的著作权归各自作者所有. 以下代码 ...

  7. SimpleAuthenticationInfo

    public SimpleAuthenticationInfo(Object principal, Object hashedCredentials, ByteSource credentialsSa ...

  8. k8s解析service地址方式

    [root@k8s-master ~]# dig -t A kubernetes.default.svc.cluster.local. @10.96.0.10 ; <<>> D ...

  9. 编程题目 定义栈的数据类型,请在类型中实现一个能够得到栈最小元素的minx函数。

    首先自己用 节点 实现了 栈 这种数据类型 为了实现题目了要求,我使用的两个栈. 一个栈 用来 push pop 用户的数据, 另外一个栈用来存放 最小元素(涉及元素比较) 代码如下: #!/usr/ ...

  10. 【LeetCode】三角形最小路径和

    [问题]给定一个三角形,找出自顶向下的最小路径和.每一步只能移动到下一行中相邻的结点上.例如,给定三角形: [ [], [,], [,,], [,,,] ] 自顶向下的最小路径和为 (即, + + + ...