block引用外部变量,是在block_impl_struct上创建新的变量,然后引用外部变量值或指针,但是block认为其内部引用的外部变量和外部变量是统一体,所以始终遵循一个原则(以下简称一致原则):
在进行改值操作时,必须使变量在block内外保持一致
当使用__block修饰的时候,就可以把引用的外部变量转变为结构体(在关于block(一)中有讲到),类似于OC的对象,block内引用结构体的指针,当改变外部变量时,只需要改变结构体内部成员变量的值就可以,结构体指针不会变,block内外变量结构体保持一致
代码1
int notChange =77;
void(^myBlock)(void) = ^() {
printf("ss--%d\n",notChange);
};
myBlock();
上面的代码,notchange在block内外的地址不一样;
原因:myBlock的内部引用了notChange的值,而不是地址,相当于重新创建了个一个int内存,所以地址不一样。
代码2
__block int h =9;
__block char *string = str;
NSMutableString * string0 = [[NSMutableString alloc] initWithString:@"123"];
void(^staBlock1)(void) = ^{
h =13;
string ="bbss";
string0 = [NSMutableString stringWithString:@"1111"];
[string0 appendString:@"456"];
printf("%s\n",str);
};
staBlock1();
上面的代码:
1.基本类型h在block内改变值时,必须用__block,否则不被允许
原因:因为block内的h和block外的地址不一样,赋值就相当于在block内进行这样的操作:int local = h;local = 13;
,h在block外部并没有变化,由于这里h要关联block内外,那么必须要使用__block,将外部基本类型变量转化为结构体,通过block引用结构体的指针来同时改变变量在block内部和外部的值
一致原则:因为h在block内外地址不一样,所以对block内部的变量直接赋值就违背了一致原则,导致变量内外不一致;
2.字符串的赋值,也必须要使用__block
原因:虽然这里block引用的是string的指针,这时候用指针进行赋值string = "bbss";
,那么就是让string指向字符串的首地址,在改变指针的指向,不符合一致原则
3.OC对象NSMutableString修改,直接引用就可以
原因:其实OC对象进行直接赋值也是不被允许的string0 = [NSMutableString stringWithString:@"1111”];
;从这里可以看出,在block内不得更改变量的指针指向,除非使用__block。但是,对对象内部的值进行更改是没有问题的,就像这段代码[string0 appendString:@"456”];
。
代码3
int test =99;
int *tt = &test;
^{
//test = test + 9;
*tt = *tt +9;
}();
从上面代码可以看出,对test直接更改test = test + 9;
违背了一致原则,所以报错了;
而使用指针tt 却是可以的,这是因为使用test指针时,block引用的会是指针tt,代码*tt = *tt + 9;
只修改了指针指向的内存块内的值,并没有修改指针本身,这样block内外值都一样,在block结束后,test的值等于108,所以符合一致原则