__block-修改变量
2020-10-27 本文已影响0人
越天高
01
在block内部修改外部的变量,不可以直接修改,因为那个age的作用域和block执行函数不再同一个作用域,改成static,或者全局可以改
如果不想用的话,就要用到__block关键字
02本质
__block可以用于解决block内部无法修改auto变量值的问题
__block不能修饰全局变量、静态变量(static)
编译器会将__block变量包装成一个对象
Person *p = [Person new];
__block int age = 10;
block = ^{
age = 12;
NSLog(@"%i", age);12
};
block();
NSLog(@"%@", age);12
一旦我们使用了__block来修饰auto变量,block在内存中的结构就会发生改变,在捕获这个变量的时候,不是简单的传值了,int age = 10;也会对这句进行包装
__attribute__((__blocks__(byref))) __Block_byref_age_0 age = {(void*)0,(__Block_byref_age_0 *)&age, 0, sizeof(__Block_byref_age_0), 10}
struct __Block_byref_age_0 {
void *__isa;
__Block_byref_age_0 *__forwarding;//
int __flags;
int __size;
int age;//外面的那个值放在这里
};
struct __main_block_impl_0 {
struct __block_impl impl;
struct __main_block_desc_0* Desc;
__Block_byref_age_0 *age; // by ref指向那个结构体
__main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, __Block_byref_age_0 *_age, int flags=0) : age(_age->__forwarding) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
当我们设置12的时候他会先难道age那个指针,找到age结构体,然后在访问forwarding指针,然后找到age进行修改
如果在block里面丢改NSMutableArry的内容不会报错,因为他是使用这个指针,而不是更改这个指针。
[图片上传失败...(image-eaafca-1603369164698)]
03细节
外面的age和里面结构体的age是不是同一个age,
我们可以手动将源码拿过来给让block转成我们自己手动的结构体,打印block结构体里面的age的地址不一样,而是和age结构体里面的age地址一样。但是苹果为了让开发者看起来age是同一个,直接打印出来的age是一样的。屏蔽了内部的实现
typedef void(^MyBlock)(void);
struct __block_impl {
void *isa;
int Flags;
int Reserved;
void *FuncPtr;
};
struct __Block_byref_age_0 {
void *__isa;//8
struct __Block_byref_age_0 *__forwarding;//8
int __flags;//4
int __size;//4
int age;
};
struct __main_block_desc_0 {
size_t reserved;
size_t Block_size;
void (*copy)(void);
void (*dispose)(void);
};
struct __main_block_impl_0 {
struct __block_impl impl;
struct __main_block_desc_0* Desc;
struct __Block_byref_age_0 *age; // by ref//0x0000000100580f20
};
int main(int argc, const char * argv[]) {
@autoreleasepool
{
MyBlock block;
__block int age = 10;
block = ^{
age = 12;
NSLog(@"%p", &age);
};
block();
struct __main_block_impl_0 *myBlock = (__bridge struct __main_block_impl_0 *)block;
NSLog(@"%p", &age);
}
return 0;
}
打印结果
可以计算出访问的age是我们这个age结构里面的age成员相当于他的地址加上10进制的20,