黑马程序员---OC学习笔记之block访问外部变量【重点面试】

来源:互联网 发布:海尔ife矩阵 编辑:程序博客网 时间:2024/04/30 20:21
------Java培训、Android培训、iOS培训、.Net培训--------

1、block可以访问外部变量么?

block时,如果里面用到外部变量,会先把外部变量从栈区【以const的方式拷贝】到【堆区(block是对象,一般在堆区)】。因此可以访问外部变量的值,但是无法改变外部变量的值。

 

【例如】

//定义一个外部变量    int sum = 2;       //定义一个有参有返回值的block的别名    typedef int (^myBlock)(int, int);    //此时myBlock是一个类型,不再是一个单纯的变量了    NSLog(@"sum = %p",&sum);//此时sum在栈区       //当block时,如果里面用到外部变量,会先把外部变量从栈区【以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内部中外部变量是只读的。

0 0
原创粉丝点击