1、block可以访问外部变量么? 当block时,如果里面用到外部变量,会先把外部变量从栈区【以const的方式拷贝】到【堆区(block是对象,一般在堆区)】。因此可以访问外部变量的值,但是无法改变外部变量的值。
【例如】 - //定义一个外部变量
- int sum = 2;
-
- //定义一个有参有返回值的block的别名
- typedef int (^myBlock)(int, int);
- //此时myBlock是一个类型,不再是一个单纯的变量了
- NSLog(@"sum = %p",&sum);//此时sum在栈区
-
- //当block时,如果里面用到外部变量,会先把外0部变量从栈区【以const的方式拷贝】到【堆区(block是对象,一般在堆区)】。
- myBlock b1 = ^(int a, int b){
- NSLog(@"sum = %p",&sum);//此时的地址不在栈区,而在堆区
- //sum = a + b;//不能改变sum的值,会报错
- //可以外部变量sum的值
- return sum + a + b;
- };
- NSLog(@"sum = %p",&sum);//此时sum在栈区
- NSLog(@"a + b = %d", b1(1,2));
- 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内部定义的变量是在【栈区】分配空间的 【例如】 - //定义一个外部变量
- int sum = 2;
-
- //定义一个有参有返回值的block的别名
- typedef int (^myBlock)(int, int);
- NSLog(@"sum = %p",&sum);//此时sum在栈区
-
- myBlock b1 = ^(int a, int b){
- int sum = 100;
- NSLog(@"内部sum = %p",&sum);//此时的地址在栈区
- return sum + a + b;
- };
- NSLog(@"a + b = %d", b1(1,2));
- 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修饰外部变量 - //定义一个外部变量,__block使得这个变量能在block创建时不是以const方式拷贝,也就是说可以修改
- __block int sum = 2;
-
- //定义一个有参有返回值的block的别名
- typedef int (^myBlock)(int, int);
- NSLog(@"sum = %p",&sum);//此时sum在栈区
-
- myBlock b1 = ^(int a, int b){
- sum = 100;//此时就允许修改
- NSLog(@"内部sum = %p",&sum);//此时的地址在堆区
- return sum + a + b;
- };
- NSLog(@"a + b = %d", b1(1,2));
-
- 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内部中外部变量是只读的。
|