我們都知道: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不允許修改外部變量的值,其實是不允許修改棧中指針的內存地址。如果將變量的棧中內存地址放到堆中,棧區是不能修改,堆區才能修改