美文网首页
iOS Block学习笔记(五) -- Block截获静态变量(

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

作者: brownfeng | 来源:发表于2018-11-23 16:05 被阅读22次

    上一节分析了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

    相关文章

      网友评论

          本文标题:iOS Block学习笔记(五) -- Block截获静态变量(

          本文链接:https://www.haomeiwen.com/subject/wzijqqtx.html