A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

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内部中外部变量是只读的。



11 个回复

倒序浏览
赞谢谢分享
回复 使用道具 举报
感谢分享,虽然目前看不懂
回复 使用道具 举报

要不要跑过去呢?  哈哈哈
要不要跑过去呢?  哈哈哈
要不要跑过去呢?  哈哈哈
回复 使用道具 举报
又有得学了,自己要好好加油
回复 使用道具 举报
赞一个,虽然现在还看不懂!
回复 使用道具 举报
大神,求抱大腿
回复 使用道具 举报
liury 中级黑马 2015-11-26 12:14:55
8#
总结的不错
回复 使用道具 举报
总结的不错
回复 使用道具 举报
收藏了,学到的时候在回来看
回复 使用道具 举报
面试时候看
回复 使用道具 举报
学到了!!!
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马