一、捕获自动变量值

首先看一个经典block面试题:
  1. int val = 10;
  2. void (^blk)(void) = ^{printf("val=%d\n",val);};
  3. val = 2;
  4. blk();

上面这段代码,输出值是:val = 10.而不是2.

block 在实现时就会对它引用到的它所在方法中定义的栈变量进行一次只读拷贝,然后在 block 块内使用该只读拷贝;换句话说block截获自动变量的瞬时值;或者block捕获的是自动变量的副本。(我更喜欢这么理解:block捕获变量的机制更像是函数按值传递)

由于block捕获了自动变量的瞬时值,所以在执行block语法后,即使改写block中使用的自动变量的值也不会影响block执行时自动变量的值。

所以,上面的面试题的结果是2不是10

__block说明符

    前面讲过block所在函数中的,捕获自动变量。但是不能修改它,不然就是“编译错误”。但是可以改变全局变量、静态变量、全局静态变量。其实这两个特点不难理解:
    ● 不能修改自动变量的值是因为:block捕获的是自动变量的const值,名字一样,不能修改
    ● 可以修改静态变量的值:静态变量属于类的,不是某一个变量。由于block内部不用调用self指针。所以block可以调用。
    解决block不能修改自动变量的值,这一问题的另外一个办法是使用__block修饰符。
  1. __block int val = 10;
  2. void (^blk)(void) = ^{printf("val=%d\n",val);};
  3. val = 2;
  4. blk();

上面的代码,跟第一个代码段相比。只是多了一个__block修饰符。但是输出结果确是2了。

__block 变量的内部实现要复杂许多,__block 变量其实是一个结构体对象,拷贝的是指向该结构体对象的指针。

二、捕获OC对象

对于捕获ObjC对象,不同于基本类型;Block会引起对象的引用计数变化。
  1. @interface MyClass : NSObject {
  2. NSObject* _instanceObj;
  3. }
  4. @end
  5. @implementation MyClass
  6. NSObject* __globalObj = nil;
  7. - (id) init {
  8. if (self = [super init]) {
  9. _instanceObj = [[NSObject alloc] init];
  10. }
  11. return self;
  12. }
  13. - (void) test {
  14. static NSObject* __staticObj = nil;
  15. __globalObj = [[NSObject alloc] init];
  16. __staticObj = [[NSObject alloc] init];
  17. NSObject* localObj = [[NSObject alloc] init];
  18. __block NSObject* blockObj = [[NSObject alloc] init];
  19. typedef void (^MyBlock)(void) ;
  20. MyBlock aBlock = ^{
  21. NSLog(@"%@", __globalObj);
  22. NSLog(@"%@", __staticObj);
  23. NSLog(@"%@", _instanceObj);
  24. NSLog(@"%@", localObj);
  25. NSLog(@"%@", blockObj);
  26. };
  27. aBlock = [[aBlock copy] autorelease];
  28. aBlock();
  29. NSLog(@"%d", [__globalObj retainCount]);
  30. NSLog(@"%d", [__staticObj retainCount]);
  31. NSLog(@"%d", [_instanceObj retainCount]);
  32. NSLog(@"%d", [localObj retainCount]);
  33. NSLog(@"%d", [blockObj retainCount]);
  34. }
  35. @end
  36. int main(int argc, charchar *argv[]) {
  37. @autoreleasepool {
  38. MyClass* obj = [[[MyClass alloc] init] autorelease];
  39. [obj test];
  40. return 0;
  41. }
  42. }

执行结果为1 1 1 2 1。
__globalObj和__staticObj在内存中的位置是确定的,所以Block copy时不会retain对象。
_instanceObj在Block copy时也没有直接retain _instanceObj对象本身,但会retain self。所以在Block中可以直接读写_instanceObj变量。
localObj在Block copy时,系统自动retain对象,增加其引用计数。
blockObj在Block copy时也不会retain。

最新文章

  1. c#生成静态html文件,封装类
  2. Java中常用修饰符使用汇总
  3. 二级联动banner【墨芈原创,大神勿喷】
  4. Mysql数据库登录问题:Your password has expired.
  5. spring mvc和spring配置扫描包问题
  6. angular模板加载 ----ng-template
  7. 《学习OpenCV》练习题第四章第一题b&c
  8. CNZZ每天百亿条日志写入,SLS+ODPS轻松拆招
  9. PCL—低层次视觉—关键点检测(rangeImage)
  10. Spring实例化bean的三种方法
  11. MySql 如何实现不同数据库同步【2个】
  12. IE6 margin 双倍边距解决方案
  13. React Native如何添加自定义图标
  14. getcomputedstyle()获取border像素差异问题
  15. [one day one question] Vue单页面应用如何保证F5强刷不清空数据
  16. strtok函数读写冲突问题
  17. .net 简单实用Log4net(多个日志配置文件)
  18. C/C++字符串使用整理
  19. netcore程序部署及守护
  20. 使用 float 存储小数?

热门文章

  1. 。【自学总结 3】------3ds Max 主工具栏
  2. How To Use DBLink In Oracle Forms 6i
  3. Hosts文件的使用
  4. win7 用户目录
  5. ARM处理器的寄存器
  6. 跨站脚本 XSS<一:介绍>
  7. cellery ImportError & AttributeError
  8. CodeForces 166B (凸包)
  9. JMS消息中间件系列[ActiveMQ](一)
  10. MDK的一些设置(尤其是部分代码无法断点问题的解决)