场景:
int age = 10;
Block block1 = ^{
age = 20;
};
不可以在block内部直接修改age的原因:
- 将以上代码转为C++(
xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc -fobjc-arc -fobjc-runtime=ios-8.0.0 main.m
)如下:
//1
struct __main_block_impl_0 {
struct __block_impl impl;
struct __main_block_desc_0* Desc;
int age;
__main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int _age, int flags=0) : age(_age) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
//2
static void __main_block_func_0(struct __main_block_impl_0 *__cself) {
int age = __cself->age;
}
//3
int main(int argc, const char * argv[]) {
/* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool;
int age = 10;
Block block = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, age);
((void (*)(__block_impl *))((__block_impl *)block)->FuncPtr)((__block_impl *)block);
}
return 0;
}
由以上代码可知:
1.局部变量age
是在main
函数中声明的,
2.接下来的操作是想在__main_block_func_0
中修改main
函数中的age
,显然是不可能的。
3.__main_block_func_0
中的age
是block通过值传递的方式捕获到的age
。如何修改:
1.用static
修饰age
或将age
定义为全局变量;
缺点:只是临时使用一下,如果使用static
或全局变量,那这个数据就会一直在内存中。
2.用__block
。
__block的本质
- 编译器会将
__block
变量包装成一个对象,如:__Block_byref_age_0
:
__block int age = 10;
struct __Block_byref_age_0 {
void *__isa; //0
__Block_byref_age_0 *__forwarding; //&age:指向自身的指针
int __flags;//0
int __size;//sizeof(__Block_byref_age_0)
int age; //10
};
应用:
-
__block
可以用于解决block内部无法修改auto
变量值的问题; -
__block
不能修饰全局变量、静态变量(static
);
思考1:
NSMutableArray *arr = [NSMutableArray array];
Block block = ^{
[arr addObject:@"123"];
};
block;
需要加__block
吗?
- 不需要;
- 因为这只是使用
arr
,并不是修改*arr
这个指针存储的值。
思考2:
-
__block
变量为什么有一个指向自己的指针*__forwarding
?