您的位置:首页 > 职场人生

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

2015-10-08 15:07 447 查看
------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内部中外部变量是只读的。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: