iOS Block学习笔记(五) -- Block截获静态变量(

2018-11-23  本文已影响22人  brownfeng

上一节分析了Block截获int, char*类型自动变量的源码, 发现Block内部用成员变量的形式保存了被截获的自动变量的值, 因此直接在Block内部修改值, 外部的自动变量的值并不会修改, 因此, 要修改变量的值, 我们使用以下三种变量应该可以:

int global_val = 1;
static int static_global_val = 2;

int main() {
  static int static_val = 3;
  void (^blk)() = ^ {
    global_val *= 1;
    static_global_val *= 2;
    static_val *= 3;
  }
  return 0;
}

此时以下部分发生改变:

int global_val = 1;
static int static_global_val = 2;

struct __block_impl {
  void *isa;
  int Flags;
  int Reserved;
  void *FuncPtr;
};

struct __main_block_impl_0 {
  struct __block_impl impl;
  struct __main_block_desc_0* Desc;
  int *static_val; // 需要内部存储静态局部变量的地址.

  //构造函数中需要传入 `*_static_val`, 也就是指向静态局部变量的指针
  __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int *_static_val, int flags=0) : static_val(_static_val) {
    impl.isa = &_NSConcreteStackBlock;
    impl.Flags = flags;
    impl.FuncPtr = fp;
    Desc = desc;
  }
};

//3. 成员函数, 在执行时, 是的是Block变量的成员变量
static void __main_block_func_0(struct __main_block_impl_0 *__cself) {
  // 静态局部变量,获取静态局部变量的地址, 
  int *static_val = __cself->static_val; 

  global_val *= 1; // 全局变量, 可以直接使用
  static_global_val *= 2; // 静态全局变量, 可以直接使用
  (*static_val) *= 3; // 静态局部变量,通过地址设置值
}

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)};


int main(){
  static int static_val = 3;

  //创建Block变量时, 需要传入static_val的地址. 在Block结构体内部, 通过指针保存静态局部变量的地址,用来完成
  void (*blk)() = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, &static_val));

  return 0;
}

结论:

使用全局变量/静态全局变量时, Block是没有对这两类变量进行特殊处理的, 直接在FunPtr中进行修改. 而使用静态局部变量时, 在Block结构体内部用一个成员指针去指向捕获静态局部变量的地址, 在Block执行时, 直接从捕获的地址中修改该静态局部变量的值.

参考资料

  1. <<Objective-C 高级编程: iOS与OSX多线程和内存管理>>
  2. https://blog.csdn.net/deft_mkjing/article/details/53149629
上一篇 下一篇

猜你喜欢

热点阅读