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同其他普通的变量类似, ...
随机推荐
- [问题2014S02] 复旦高等代数II(13级)每周一题(第二教学周)
问题2014S02 设实系数多项式 \begin{eqnarray*}f(x) &=& a_nx^n+a_{n-1}x^{n-1}+\cdots+a_1x+a_0, \\ g(x) ...
- ATI Radeon HD 5450 with full QE/CI Support ( 转载 )
ATI Radeon HD 5450 with full QE/CI Support - DSDT (Contains HDMI Audio Edit Too) & AGPM included ...
- Spring 定时任务1
转载自 http://blog.csdn.net/prisonbreak_/article/details/49180307 Spring配置文件xmlns加入 xmlns:task="ht ...
- Winform中checklistbox控件的常用方法
Winform中checklistbox控件的常用方法最近用到checklistbox控件,在使用其过程中,收集了其相关的代码段1.添加项checkedListBox1.Items.Add(" ...
- 通过HWND获得CWnd指针
cwnd 又为计算机网络中拥塞窗口(congestion window)的简写.拥塞窗口的大小取决于网络的拥塞程度,并且动态地在变化.发送方让自己的发送窗口还可能小于拥塞窗口. CWnd是MFC窗口类 ...
- Web服务器amp搭建
- IE浏览器bug罪魁祸首--hasLayout
IE浏览器一直都是前端程序员最头疼的,IE的表现与其他浏览器不同的原因之一就是,显示引擎使用一个称为布局(layout)的内部概念. 认识hasLayout--haslayout是Windows In ...
- 简单说一下printf("%*s%s",xx,xx,xx);或printf("%*s\n",xx,xx);
大家还记得这个例子吗 #include "public.h" int main() { ; printf("%4d\n",a); ; } 这个输出结果为: ...
- Nginx 1.10.2 php 7 环境安装
1.安装编译工具和库文件,红色部分提示在centos镜像站点上查不到包,用yum安装的时候要认真看那些包没有找到,用yum的时候尽量不要使用-y选项 yum install gcc automake ...
- neon指令,注意事项
1. vbic_s8 (int8x8_t a, int8x8_t b) 是 ~(ai & bi),一开始理解成 (~ai )& bi 导致出错 2.uint8x8_t vqshrn ...