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同其他普通的变量类似, ...
随机推荐
- 4 .Swift函数|闭包
在编程中,我们常把能完成某一特定功能的一组代码,并且带有名字标记类型叫做函数,在C语言中,我们知道函数名就是一个指针,它指向了函数体内代码区的第一行代码的地址,在swift中也具有同样的功效. 在Sw ...
- new一个数组,delete释放内存
int *a = new int[4]; for(int i=0;i<4;i++) { a[i] = i; printf("a[%d]=%d\n", i, i); } del ...
- Android学习简单总结
1: 主要的view控件: 文字: TextView 图片: ImgView 视频:SurfaceView ... 2:控件 PopupWindow 实现类似左边导航栏 tabhost实现顶部或者下部 ...
- shockt通信
目前为止,我们使用的最多网络协议还是tcp/ip网络.通常来说,我们习惯上称为tcp/ip协议栈.至于协议栈分成几层,有两种说法.一种是五层,一种是七层. 5.应用层 4.传输层 3.网络 ...
- 基础笔记6(exception)
1.异常:一种处理错误的机制,将错误和业务分离. throwable的子类 error 和exception exception 分两类:checked (需要捕获处理或者抛出)和unchecked( ...
- openfire源码修改聊天消息发送内容
/** * $RCSfile: MessageRouter.java,v $ * $Revision: 3007 $ * $Date: 2005-10-31 13:29:25 -0300 (Mon, ...
- SPSS数据分析—相关分析
相关系数是衡量变量之间相关程度的度量,也是很多分析的中的当中环节,SPSS做相关分析比较简单,主要是区别如何使用这些相关系数,如果不想定量的分析相关性的话,直接观察散点图也可以. 相关系数有一些需要注 ...
- 【apache】yum 安装Apache(Centos 6.5)
一.首先在系统上面查询一下是否已经安装了apache [Apache在linux系统里的名字是httpd] rpm -qa httpd 如果有返回的信息,则会显示已经安装的软件.如果没有则 ...
- OpenBSD为何还在用CVS之感
一个轻松无聊的晚上突然想到一个问题——在当今这个Git大红大紫的时代,OpenBSD为何还在用CVS代码仓库?连他同阵营的FreeBSD都已经改用SVN,宣布逐渐废掉CVS了……问了下google,搜 ...
- 0506--Scrum项目1.0
应用NABCD模型,分析你们初步选定的项目,充分说明你们选题的理由. 录制为演说视频,上传到视频网站,并把链接发到团队博客上. 团队项目选题 四则运算 NABCD 模型 1) N (Need 需求) ...