如何使用Block来修改外部变量
我们都知道:block 是不允许修改外部变量的,这里所说的外部变量的值,指得是栈中指针的内存地址。__Block 的作用是只要观察到该变量被被Block所持有,就将"外部变量"在栈中的内存地址放到了堆中。进而在Block内部也可以修改外部变量的值。
1.例如:修改基本数据类型值中的Int 类型(浮点型一样的道理)
-(void)testBlock{
__block
int a =0;
NSLog(@"定义前:%p,a ===%d",&a,a);
void(^foo)(NSString*name) = ^(NSString*str){
a =1;
NSLog(@"block内部,a ====%d :%p",a,&a);
};
foo(@"1111");
NSLog(@"定以后:%p,a === %d",&a,a);
}
运行结果如下:
NewCocoTest[1316:35458]定义前:0x7fff56bdc7b8,a ===0
2017-02-20 10:12:16.867 NewCocoTest[1316:35458] block内部,a ====1 :0x600000033998
2017-02-20 10:12:16.867 NewCocoTest[1316:35458]定以后:0x600000033998,a === 1
加上__Block 以后就产生了浅拷贝,内存地址由原来的栈区,变成了堆区。
2.修改基本数据类型中的char 类型
例子:
-(void)testBlockTwo{
NSMutableString*a = [NSMutableStringstringWithFormat:@"Tom"];
NSLog(@"定义以前a指向的堆中地址;%p,a在栈中的指针地址:%p,a ======%@",a,&a,a);
void(^foo)(void) = ^{
a.string=@"Jeery";
NSLog(@"block内部a指向的堆中地址:%p,a在栈中的指针地址%p,a ======%@",a,&a,a);
};
foo();
NSLog(@"Block以后a在堆中的地址%p,a在栈中的指针地址%p,a ======%@",a,&a,a);
}
运行结果如下:
NewCocoTest[1316:35458]定义以前a指向的堆中地址;0x608000275e80,a在栈中的指针地址:0x7fff56bdc7b8,a ======Tom
2017-02-20 10:12:16.868 NewCocoTest[1316:35458] block内部a指向的堆中地址:0x608000275e80,a在栈中的指针地址0x600000045f30,a ======Jeery
2017-02-20 10:12:16.868 NewCocoTest[1316:35458] Block以后a在堆中的地址0x608000275e80,a在栈中的指针地址0x7fff56bdc7b8,a ======Jeery
这里的a已经由基本数据类型,变成了对象类型。block会对对象类型的指针进行copy,copy到堆中,但并不会改变该指针所指向的堆中的地址,block体内修改的实际是a指向的队中的内容。
总结:Block不允许修改外部变量的值,其实是不允许修改栈中指针的内存地址。如果将变量的栈中内存地址放到堆中,栈区是不能修改,堆区才能修改