__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,

上一篇下一篇

猜你喜欢

热点阅读