【block第四篇】实现
来源:互联网 发布:金蝶软件资产负债表 编辑:程序博客网 时间:2024/05/29 17:22
-------------------------------------------欢迎查看block连载博客【专栏】--------------------------------------
【block编程第一篇】block语法 【block编程第二篇】block捕获变量和对象;
【block编程第三篇】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();}
【注】:以上题目摘自:CocoaChina论坛打开链接
二、block的定义
Block是C语言的扩充功能。可以用一句话来表示Blocks的扩充功能:带有自动变量(局部变量)的匿名函数。命名就是工作的本质,函数名、变量名、方法名、属性名、类名和框架名都必须具备。而能够编写不带名称的函数对程序员来说相当有吸引力。
三、block的实现
int main(){ void (^blk)(void) = ^{printf("block\n");}; blk(); return 0;}
struct __block_impl{ void *isa; int Flags; int Reserved; void *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{ void *isa; int Flags; int Reserved; void *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{ void *isa; int Flags; int Reserved; void *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{ void *__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;};}
-(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; int *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; int *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测试题答案:ABABB
- 【block第四篇】实现
- 第四十三篇:iOS链式编程Block
- block实现
- Block实现
- Android特效第四篇:Android抽屉实现
- FPGA第四篇:异步串口的实现
- UIActionsheet的block实现
- block实现场景切换
- block 实现原理
- Block实现委托机制
- block底层实现原理
- Block的实现原理
- block的实现原理
- block实现原理详解
- block 实现原理详解
- block的实现原理
- Block实现原理
- block的底层实现
- 【UVaOJ】127 - "Accordian" Patience
- Java线程(五):Timer和TimerTask
- 安卓----自定义控件
- Unity3d 中的 A*寻路
- Linux进程间通信——使用消息队列
- 【block第四篇】实现
- Git下的冲突解决
- Java线程(三):线程协作-生产者/消费者问题
- 学习蓝牙
- SQLServer 数据库镜像+复制切换方案
- 六十九 windows7 telent 使用
- VMware centos系统联网解决方案
- 2014年最酷的30个JavaScript库
- Winform窗口弹出位置控制