block的内部实现
主要内容:
一、block相关的题目
二、block的定义
三、block的实现
四、捕获自动变量值
五、block存储区域
六、截获对象
一、block相关的题目
这是一篇比较长的博文,前部分是block的测试题目,中间是block的语法、特性,block讲解block内部实现和block存储位置,请读者耐心阅读。具备block基础的同学,直接调转到block的实现
下面列出了五道题,看看能否答对两三个。主要涉及block栈上、还是堆上、怎么捕获变量。答案在博文最后一行
- //-----------第一道题:--------------
- void exampleA() {
- char a = 'A';
- ^{ printf("%c\n", a);};
- }
- A.始终能够正常运行 B.只有在使用ARC的情况下才能正常运行
- C.不使用ARC才能正常运行 D.永远无法正常运行
- //-----------第二道题:答案同第一题--------------
- void exampleB_addBlockToArray(NSMutableArray *array) {
- char b = 'B';
- [array addObject:^{printf("%c\n", b);}];
- }
- void exampleB() {
- NSMutableArray *array = [NSMutableArray array];
- exampleB_addBlockToArray(array);
- void (^block)() = [array objectAtIndex:0];
- block();
- }
- //-----------第三道题:答案同第一题--------------
- void exampleC_addBlockToArray(NSMutableArray *array) {
- [array addObject:^{printf("C\n");}];
- }
- void exampleC() {
- NSMutableArray *array = [NSMutableArray array];
- exampleC_addBlockToArray(array);
- void (^block)() = [array objectAtIndex:0];
- block();
- }
- //-----------第四道题:答案同第一题--------------
- typedef void (^dBlock)();
- dBlock exampleD_getBlock() {
- char d = 'D';
- return ^{printf("%c\n", d);};
- }
- void exampleD() {
- exampleD_getBlock()();
- }
- //-----------第五道题:答案同第一题--------------
- typedef void (^eBlock)();
- eBlock exampleE_getBlock() {
- char e = 'E';
- void (^block)() = ^{printf("%c\n", e);};
- return block;
- }
- void exampleE() {
- eBlock block = exampleE_getBlock();
- block();
- }
二、block的定义
Block是C语言的扩充功能。可以用一句话来表示Blocks的扩充功能:带有自动变量(局部变量)的匿名函数。命名就是工作的本质,函数名、变量名、方法名、属性名、类名和框架名都必须具备。而能够编写不带名称的函数对程序员来说相当有吸引力。
三、block的实现
- int main(){
- void (^blk)(void) = ^{printf("block\n");};
- blk();
- return 0;
- }
- struct __block_impl{
- voidvoid *isa;
- int Flags;
- int Reserved;
- voidvoid *FuncPtr;
- };
- static struct __main_block_desc_0{
- unsigned long reserved;
- unsigned long Block_size
- }__main_block_desc_0_DATA = { 0, sizeof(struct __main_block_impl_0)};
- struct __main_block_impl_0{
- struct __block_impl impl;
- struct __main_block_desc_0 *Desc;
- }
- static struct __main_block_func_0(struct __main_block_impl_0 *__cself)
- {
- printf("block\n");
- }
- int main(){
- struct __main_block_impl_0 *blk = &__main_block_impl_0(__main_block_func_0,&__main_block_desc_0_DATA);
- (*blk->impl.FuncPtr)(blk);
- }
__main_block_impl_0:block变量。
__main_block_func_0:虽然,block叫,匿名函数。但是,这个函数还是被编译器起了个名字。
__main_block_desc_0:block的描述,注意,他有一个实例__main_block_desc_0_DATA
- __main_block_impl_0{
- voidvoid *isa;
- int Flags;
- int Reserved;
- voidvoid *FuncPtr;
- struct __main_block_desc_0 *Desc;
- }
四、捕获自动变量值
- int val = 10;
- void (^blk)(void) = ^{printf("val=%d\n",val);};
- val = 2;
- blk();
上面这段代码,输出值是:val = 10.而不是2,点击这里查看【block第二篇】block捕获变量和对象。
- __main_block_impl_0{
- voidvoid *isa;
- int Flags;
- int Reserved;
- voidvoid *FuncPtr;
- struct __main_block_desc_0 *Desc;
- int val;
- }
- int main(){
- struct __main_block_impl_0 *blk = &__main_block_impl_0(__main_block_func_0,&__main_block_desc_0_DATA,val);
- }
注意函数调用最后一个参数,即val参数。
- static struct __main_block_func_0(struct __main_block_impl_0 *__cself)
- {
- printf("val=%d\n",__cself-val);
- }
__block说明符
- __block int val = 10;
- void (^blk)(void) = ^{val = 1;};
- struct __block_byref_val_0{
- voidvoid *__isa;
- __block_byref_val_0 *__forwarding;
- int _flags;
- int __size;
- int val;
- }
五、block存储区域
- typedef int (^blk_t)(int);
- for(...){
- blk_t blk = ^(int count) {return count;};
- }
block的话就是返回局部变量的指针。而这一点恰是编译器已经断定了。在ARC下没有这个问题,是因为ARC使用了autorelease了。
- -(id) getBlockArray{
- int val =10;
- return [[NSArray alloc]initWithObjects:
- ^{NSLog(@"blk0:%d",val);},
- ^{NSLog(@"blk1:%d",val);},nil];
- }
- id obj = getBlockArray();
- typedef void (^blk_t)(void);
- blk_t blk = (blk_t){obj objectAtIndex:0};
- blk();
- typedef int (^blkt1)(void) ;
- -(void) stackOrHeap{
- __block int val =10;
- intint *valPtr = &val;//使用int的指针,来检测block到底在栈上,还是堆上
- blkt1 s= ^{
- NSLog(@"val_block = %d",++val);
- return val;};
- s();
- NSLog(@"valPointer = %d",*valPtr);
- }
调用copy之后的结果呢:
- -(void) stackOrHeap{
- __block int val =10;
- intint *valPtr = &val;//使用int的指针,来检测block到底在栈上,还是堆上
- blkt1 s= ^{
- NSLog(@"val_block = %d",++val);
- return val;};
- blkt1 h = [s copy];
- h();
- NSLog(@"valPointer = %d",*valPtr);
- }
在ARC下>>>>>>>>>>>无效果。 val_block = 11 valPointer = 10
__block变量存储区域
六、截获对象
- static void __main_block_copy_0(struct __main_block_impl_0 *dst, struct __main_block_impl_0 *src){
- _Block_objct_assign(&dst->val,src->val,BLOCK_FIELD_IS_BYREF);
- }
- static void __main_block_dispose_0(struct __main_block_impl_0 *src){
- _block_object_dispose(src->val,BLOCK_FIELD_IS_BYREF);
- }
__block修饰符可用于任何类型的自动变量
【__block循环引用】
根据上面讲的内容,block在持有对象的时候,对象如果持有block,会造成循环引用。解决办法有两种:
1. 使用__weak修饰符。id __weak obj = obj_
2. 使用__block修饰符。__block id tmp = self;然后在block中tmp = nil;这样就打破循环了。这个办法需要记得将tmp=nil。不推荐!
block的内部实现的更多相关文章
- block的内部实现原理
一.简单定义 block是一个指向结构体的指针,编译器将block内部代码生成对应的函数,上述结构体中的函数指针(funcPtr)指向该函数的实现: 二.相关概念 形参和实参 形参:形式参数,用于定义 ...
- block反向界面传值
1.在第二个界面的.h文件中申明block @property(nonatomic,copy)void(^myBlock)(NSString * str); 2.在返回第一个界面的点击事件中赋值要传递 ...
- Block循环引用问题研究
自从苹果在objc中添加Block功能支持以后已经过了很久.目前网上对于Block的使用有很多介绍.不过对于Block的内存管理问题,则是众说纷纭.再加上objc开始使用ARC以后,对于Block的内 ...
- 浅谈 block(1) – clang 改写后的 block 结构
这几天为了巩固知识,从 iOS 的各个知识点开始学习,希望自己对每一个知识理解的更加深入的了解.这次来分享一下 block 的学习笔记. block 简介 block 被当做扩展特性而被加入 GCC ...
- iOS block 的底层实现
其实swift 的闭包跟 OC的block 是一样一样的,学会了block,你swift里边的闭包就会无师自通. 参考:http://www.jianshu.com/p/e23078c11518 ht ...
- 初始block,关于定义的几个小题目
block的定义和C语言指针函数非常相似,就可以照着指针函数的方法去依葫芦画瓢就可以了 block中的^只是用来表示这是一个block对象,和函数指针中的*作用一样,只是一个标识符 下面有三个小例子来 ...
- 深入理解block
2010年WWDC发布iOS4时Apple对Objective-C进行了一次重要的升级:支持Block.说到底这东西就是闭包,其他高级语音例如Java和C++已有支持,第一次使用Block感觉满简单好 ...
- block 实现原理详解(一)
对于大多数人来讲,block内部到底是怎样实现的呢?我们可以借助clang将其编译成为c++的代码,就可以看出,block到底是什么东西, 先来看这样一个问题, <!-- lang: cpp - ...
- iOS中Block使用探索
Block介绍 Block在ios 4.0之后加入,并大量使用在新的ios api中.block是一个匿名的代码块,可以传递给其他对象的参数,并得到返回值.从本质上讲,block同其他普通的变量类似, ...
随机推荐
- 初学画布canvas的chapter2
文本 1.字体属性 context.font = [css font property] ——使用CSS规范,语法跟CSS字体速记符号一致 ——line-height无效,并永远忽略 Context. ...
- html5 drag and drop
注:链接.图片默认是draggable的. mousemove在整个拖放的过程中不会被触发. dragStart设置: e.dataTransfer.effectAllowed = "mov ...
- CentOS6.5 mysql 5.5安装
CentOS 6 mysql5.5安装配置 1 安装所需软件 2 安装cmake 3 tar.gz形式安装mysql 4 配置与启动 MySQL自5.5版本以后,就开始使用cmake编译工具了.tar ...
- 《BI那点儿事》数据流转换——导入列、导出列
导入列: 导入列例子现在来做一个例子:创建路径D:\Pictures随便在路径D:\Pictures中粘贴4个比较小的图像文件命名为01.png.02.png.03.png.04.png在路径D:\P ...
- fifter常见的运用场景
没配置过滤器 package servlet; import java.io.IOException; import javax.servlet.ServletException; import ja ...
- windows下开启mysql远程访问
USE mysql;SELECT * FROM USER ; 直接修改user=root host=127.0.0.1为% FLUSH PRIVILEGES;
- 【ros bug】rplidar.launch is neither a launch file in package...
解决 :cd catkin_ws $ source devel/setup.bash
- GeoHash
查找是我们经常会碰到的问题,以前我做过一个这样的算法,在有序的数列(80万条左右),这批数据是根据维度由小到大排序的,寻找已知数据的位置,并且所相应的运算,由于这个算法要在嵌入式系统中做,如果一次在内 ...
- 0517 Scrum 项目4.0
Sprint 1看板: 任务认领(一种标签颜色代表一个人的任务): 许佳仪:紫色 柯晓君:红色 赖文亮:蓝色 卓宇靖:黑色 每日例会的时间:16:00 地点:课室 成员 团队贡献分 许佳仪 1 ...
- 谈谈Javascript的this关键字(this is not this)
前言: 看文章标题你就知道,这篇文章我只讲一个简单的Javascript的this关键字,说它简单——它又不简单,因为曾几何时我也对this关键字有些困惑,它也确实会让不少程序员感到不解——它像是一个 ...