黑马程序员技术交流社区

标题: OC学习笔记之block访问外部变量【重点面试】 [打印本页]

作者: chunhuayun    时间: 2015-10-10 08:20
标题: OC学习笔记之block访问外部变量【重点面试】
1、block可以访问外部变量么?
当block时,如果里面用到外部变量,会先把外部变量从栈区【以const的方式拷贝】到【堆区(block是对象,一般在堆区)】。因此可以访问外部变量的值,但是无法改变外部变量的值。

【例如】
  1. //定义一个外部变量
  2.     int sum = 2;
  3.    
  4.     //定义一个有参有返回值的block的别名
  5.     typedef int (^myBlock)(int, int);
  6.     //此时myBlock是一个类型,不再是一个单纯的变量了
  7.     NSLog(@"sum = %p",&sum);//此时sum在栈区
  8.    
  9.     //当block时,如果里面用到外部变量,会先把外0部变量从栈区【以const的方式拷贝】到【堆区(block是对象,一般在堆区)】。
  10.     myBlock b1 = ^(int a, int b){
  11.         NSLog(@"sum = %p",&sum);//此时的地址不在栈区,而在堆区
  12.         //sum = a + b;//不能改变sum的值,会报错
  13.         //可以外部变量sum的值
  14.         return sum + a + b;
  15.     };
  16.     NSLog(@"sum = %p",&sum);//此时sum在栈区
  17.     NSLog(@"a + b = %d", b1(1,2));
  18.     NSLog(@"sum = %p",&sum);//此时sum在栈区
复制代码
【打印结果】
2015-10-07 14:54:41.216 加强02[1308:303] sum =0x7fff5fbff93c
2015-10-07 14:54:41.218 加强02[1308:303] str =0x7fff5fbff930
2015-10-07 14:54:41.219 加强02[1308:303] sum =0x7fff5fbff93c
2015-10-07 14:54:41.219 加强02[1308:303] sum =0x100102e40
2015-10-07 14:54:41.219 加强02[1308:303] a + b = 5
2015-10-07 14:54:41.220 加强02[1308:303] sum =0x7fff5fbff93c

2、在block中能否定义新的变量
可以,而且在block内部定义的变量是在【栈区】分配空间的
【例如】
  1.    //定义一个外部变量
  2.     int sum = 2;
  3.    
  4.     //定义一个有参有返回值的block的别名
  5.     typedef int (^myBlock)(int, int);
  6.     NSLog(@"sum = %p",&sum);//此时sum在栈区
  7.    
  8.     myBlock b1 = ^(int a, int b){
  9.         int sum = 100;
  10.         NSLog(@"内部sum = %p",&sum);//此时的地址在栈区
  11.         return sum + a + b;
  12.     };
  13.     NSLog(@"a + b = %d", b1(1,2));
  14.     NSLog(@"外部sum = %p",&sum);//此时sum在栈区
复制代码

打印结果:
2015-10-07 15:15:29.382 加强02[1339:303] sum =0x7fff5fbff93c
2015-10-07 15:15:29.384 加强02[1339:303] 内部sum = 0x7fff5fbff904
2015-10-07 15:15:29.384 加强02[1339:303] a + b = 103
2015-10-07 15:15:29.385 加强02[1339:303] 外部sum = 0x7fff5fbff93c

3、如何做到在block内修改外部变量?
【可以】可以用__block修饰外部变量
  1.   //定义一个外部变量,__block使得这个变量能在block创建时不是以const方式拷贝,也就是说可以修改
  2.     __block int sum = 2;
  3.    
  4.     //定义一个有参有返回值的block的别名
  5.     typedef int (^myBlock)(int, int);
  6.     NSLog(@"sum = %p",&sum);//此时sum在栈区
  7.    
  8.     myBlock b1 = ^(int a, int b){
  9.         sum = 100;//此时就允许修改
  10.         NSLog(@"内部sum = %p",&sum);//此时的地址在堆区
  11.         return sum + a + b;
  12.     };
  13.     NSLog(@"a + b = %d", b1(1,2));
  14.    
  15.     NSLog(@"外部sum = %d address = %p",sum,&sum);//此时sum在堆区
复制代码

【打印结果】
2015-10-07 15:20:17.928 加强02[1358:303] sum =0x7fff5fbff938
2015-10-07 15:20:17.930 加强02[1358:303] 内部sum = 0x100301128
2015-10-07 15:20:17.930 加强02[1358:303] a + b = 103
2015-10-07 15:20:17.931 加强02[1358:303] 外部sum = 100 address =0x100301128

【分析结果】
由结果可知,外部变量A在block创建时被【非const方式拷贝到堆区中】,此时在block中就可以修改这个外部变量A,而且,在这个block之后(即block的外面),外部变量A的值已经被改变,而且地址也是堆区地址。以后外部变量A将一直使用这个地址


4、注意事项
1)全局block
2)栈block
3)堆block
4)常量变量(NSString *a = @"abc"中 a是变量,@“abc”是常量); 不加__block类型修饰,block会引用常量的地址(浅拷贝)。加__block类型修饰block会去引用【常量变量】(如:a变量,a = @“abc”,可以任意修改a指向的内容)的地址
5)如果不加__block就直接在block内部修改外部的变量,编译器会报错,此时,block内部中外部变量是只读的。




作者: daitoudainaoali    时间: 2015-11-24 02:58
赞谢谢分享
作者: cube川    时间: 2015-11-24 13:04
感谢分享,虽然目前看不懂
作者: FengLinHuoShan    时间: 2015-11-24 21:27

要不要跑过去呢?  哈哈哈
要不要跑过去呢?  哈哈哈
要不要跑过去呢?  哈哈哈
作者: cbl16888    时间: 2015-11-24 21:42
又有得学了,自己要好好加油
作者: 罗文强    时间: 2015-11-26 00:41
赞一个,虽然现在还看不懂!
作者: 私夏晓    时间: 2015-11-26 00:44
大神,求抱大腿
作者: liury    时间: 2015-11-26 12:14
总结的不错
作者: 唐阿丽    时间: 2015-11-26 13:02
总结的不错
作者: 超人不会飞啊    时间: 2015-11-26 13:40
收藏了,学到的时候在回来看
作者: qinxiaodong    时间: 2015-11-26 17:52
面试时候看
作者: x_starry    时间: 2016-4-30 13:49
学到了!!!




欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2