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#
总结的不错
回复 举报
总结的不错
回复 举报
收藏了,学到的时候在回来看
回复 举报
面试时候看
回复 举报
学到了!!!
回复 举报
您需要登录后才可以回帖 登录 | 加入黑马