天天看点

Block底层实现原理

Block

int main(int argc, const char * argv[]) {
@autoreleasepool {
    TYBlock block = ^(){
        NSLog(@"hello block");
    };
    block();
    
    NSLog(@"Hello, World!");
    }
    return 0;
}
           

clang -rewrite-objc main.m

// block 的结构体
struct __block_impl {  // block 的结构体
  void *isa;           // isa 指针 类比对象
  int Flags;           //
  int Reserved;
  void *FuncPtr;     // 函数指针, 指向block自身实现
};

// block的实现, 实现入口
struct __main_block_impl_0 {
  struct __block_impl impl;   // block类型成员变量 isa  Flags Reserved *FuncPtr;
  struct __main_block_desc_0* Desc;
  __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int flags=0) { // 结构体构造器
    impl.isa = &_NSConcreteStackBlock;
    impl.Flags = flags;
    impl.FuncPtr = fp;
    Desc = desc;
  }
};

// block 执行的函数  __main_block_func_0
static void __main_block_func_0(struct __main_block_impl_0 *__cself) { // block 要执行的静态方法
    NSLog((NSString *)&__NSConstantStringImpl__var_folders_fm_w1qcdkwj68v18gnz_z89g02c0000gn_T_main_2dcb54_mi_0);
}

// block 描述信息结构体  __main_block_desc_0
static struct __main_block_desc_0 { //        __main_block_impl_0 的描述结构体
  size_t reserved;
  size_t Block_size; // 结构体大小
} __main_block_desc_0_DATA = { 0, sizeof(struct __main_block_impl_0)};

// main函数
int main(int argc, const char * argv[]) {
/* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool;
    
    //
    /**
     block 实现
     @param 1 的静态方法
     @param 2 __main_block_desc_0 __main_block_impl_0的描述结构体
     */
    TYBlock block = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA));
    // block 调用
    ((void (*)(__block_impl *))((__block_impl *)block)->FuncPtr)((__block_impl *)block);

    NSLog((NSString *)&__NSConstantStringImpl__var_folders_fm_w1qcdkwj68v18gnz_z89g02c0000gn_T_main_2dcb54_mi_1);
}
return 0;
}
           

持有局部变量Block

int a = 10;
    TYBlock block = ^(){
        NSLog(@"hello block %d", a);
    };
    block();
           
  • cpp文件
    // block的实现入口多了一个 外部变量 int a
    struct __main_block_impl_0 {
    struct __block_impl impl;
    struct __main_block_desc_0* Desc;
    int a; // 外部变量 block访问的外部变量
      __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int _a, int flags=0) : a(_a) { // 在构造函数之前初始化变量a
      impl.isa = &_NSConcreteStackBlock;
          impl.Flags = flags;
          impl.FuncPtr = fp;
          Desc = desc;
       }
    };
    
    // 实现函数
    static void __main_block_func_0(struct __main_block_impl_0 *__cself) {
    int a = __cself->a; // 多了一个外部变量a。__main_block_impl_0中的a赋值给函数中的临时变量a
    
              NSLog((NSString *)&__NSConstantStringImpl__var_folders_fm_w1qcdkwj68v18gnz_z89g02c0000gn_T_main_df3697_mii_0, a);
          }
          
    // block的表述类
    static struct __main_block_desc_0 {
    size_t reserved;
    size_t Block_size;
    } __main_block_desc_0_DATA = { 0, sizeof(struct __main_block_impl_0)};
    
    // main函数
    int a = 10;
      TYBlock block = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, a));
      ((void (*)(__block_impl *))((__block_impl *)block)->FuncPtr)((__block_impl *)block);
      NSLog((NSString *)&__NSConstantStringImpl__var_folders_fm_w1qcdkwj68v18gnz_z89g02c0000gn_T_main_df3697_mii_1, block);
               
    block入口函数 __main_block_impl_0中多了一个成员变量(block访问的局部变量)__main_block_func_0 函数调用时。参数__main_block_impl_0中的成员变量a赋值给函数中的临时变量a。所以这种方式捕获的外部变量不可修改并且外部修改后也不能随之更改。

捕获__block 修饰局部变量

__block int a = 10;
    TYBlock block = ^(){
        NSLog(@"block内====%d", a); // 20
        a = 100;
    };
    a = 20;
    block();
    NSLog(@"block外=====%d", a); // 100
           
  • cpp
    // 封装__block修饰的外部变量
      struct __Block_byref_a_0 {
          void *__isa;                     // 对象指针
          __Block_byref_a_0 *__forwarding; // 堆中的地址 也就是指向自己的指针
          int __flags; // 标志位
          int __size;  // 结构体大小
          int a;       // 外部变量
      };
    
      struct __main_block_impl_0 {
          struct __block_impl impl;
          struct __main_block_desc_0* Desc;
          __Block_byref_a_0 *a; //  访问的外部变量a 变成__Block_byref_a_0类型的结构体指针。__block修饰的变量通过指针传递进来
          __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc,     __Block_byref_a_0 *_a, int flags=0) : a(_a->__forwarding) {
          impl.isa = &_NSConcreteStackBlock;
          impl.Flags = flags;
          impl.FuncPtr = fp;
          Desc = desc;
          }
      };
      
      static void __main_block_func_0(struct __main_block_impl_0 *__cself) {
          __Block_byref_a_0 *a = __cself->a; // bound by ref
          // a->__forwarding->a) // 堆中的a
          NSLog((NSString *)&__NSConstantStringImpl__var_folders_fm_w1qcdkwj68v18gnz_z89g02c0000gn_T_main_537bc1_mii_0, (a->__forwarding->a));
      }
      
      // 添加了copy和dispose函数为了拷贝和析构__Block_byref_a_0结构体,对改结构体进行内存管理使用
      static void __main_block_copy_0(struct __main_block_impl_0*dst, struct __main_block_impl_0*src) {
          // _Block_object_assign 函数:当block从栈拷贝到堆时,调用此函数。
          _Block_object_assign((void*)&dst->a, (void*)src->a, 8/*BLOCK_FIELD_IS_BYREF*/);
      }
      // 当block从堆释放时调用 __main_block_dispose_0函数
      static void __main_block_dispose_0(struct __main_block_impl_0*src) {
          _Block_object_dispose((void*)src->a, 8/*BLOCK_FIELD_IS_BYREF*/);
      }
      
      // 当block从堆内释放的时候调用 __main_block_impl_0 释放内存
      static struct __main_block_desc_0 {
          size_t reserved;
          size_t Block_size;
          void (*copy)(struct __main_block_impl_0*, struct __main_block_impl_0*);
          void (*dispose)(struct __main_block_impl_0*);
      } __main_block_desc_0_DATA = { 0, sizeof(struct __main_block_impl_0), __main_block_copy_0, __main_block_dispose_0};
               

block 访问的__block修饰的外部变量就是一个结构体 __Block_byref_a_0

// 封装__block修饰的外部变量
    struct __Block_byref_a_0 {
        void *__isa;                     // 对象指针
        __Block_byref_a_0 *__forwarding; // 堆中的地址 也就是指向自己的指针
        int __flags; // 标志位
        int __size;  // 结构体大小
        int a;       // 外部变量
    };
           

int a 是外部变量名。 __Block_byref_a_0 *__forwarding 这个是指向自己的指针

为了对__Block_byref_a_0 添加了copy和dispose函数为了拷贝和析构__Block_byref_a_0结构体。

__main_block_impl_0中增加了__Block_byref_a_0类型的成员变量指针。所以__block的变量可以修改,是因为指针传递。所以block内部修改了值,外部也会改变。

struct __main_block_impl_0 {
    struct __block_impl impl;
    struct __main_block_desc_0* Desc;
    __Block_byref_a_0 *a; //  访问的外部变量a 变成__Block_byref_a_0类型的结构体指针。__block修饰的变量通过指针传递进来
    __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc,     __Block_byref_a_0 *_a, int flags=0) : a(_a->__forwarding) {
    impl.isa = &_NSConcreteStackBlock;
    impl.Flags = flags;
    impl.FuncPtr = fp;
    Desc = desc;
    }
};
           

在调用函数__main_block_func_0 时,a是

static void __main_block_func_0(struct __main_block_impl_0 *__cself) {
    __Block_byref_a_0 *a = __cself->a; // 指针栈中 __Block_byref_a_0
    // a->__forwarding->a) // 堆中的a  // 堆中的forwarding 的成员变量a
    NSLog((NSString *)&__NSConstantStringImpl__var_folders_fm_w1qcdkwj68v18gnz_z89g02c0000gn_T_main_537bc1_mii_0, (a->__forwarding->a));
}
           

用__block修改后,testNum3变量转换为__Block_byref_num_0 的结构体。

// man函数 __forwarding 指向自身的指针
__attribute__((__blocks__(byref))) __Block_byref_a_0 a = {(void*)0,(__Block_byref_a_0 *)&a, 0, sizeof(__Block_byref_a_0), 10};
TYBlock block = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, (__Block_byref_a_0 *)&a, 570425344));
(a.__forwarding->a) = 20;
((void (*)(__block_impl *))((__block_impl *)block)->FuncPtr)((__block_impl *)block);
NSLog((NSString *)&__NSConstantStringImpl__var_folders_fm_w1qcdkwj68v18gnz_z89g02c0000gn_T_main_adc47b_mii_1, (a.__forwarding->a));
           

a变量用__Block_byref_a_0包裹,变成__Block_byref_a_0结构体

无论是栈上的a变量用__Block_byref_a_0还是堆中的a变量用__Block_byref_a_0。修改时都是通过变成__Block_byref_a_0 的 __forwarding中的数值。所以修改的都是堆中的__Block_byref_a_0中的a

注:static修饰的局部静态变量,没有使用__Block_byref_a_0结构体包装,直接传递指针。__Block_byref_a_0的目的是把栈上的变量拷贝到堆中,延长生命周期。接获成员变量的block是堆block也印证这一点。